Corso programmazione Android Lezione 13: L’app BeReader Parte 2
Le altre lezioni del Corso di Programmazione Android sono reperibili a questo indirizzo
In questa seconda parte continueremo l’analisi dell’APP BeReader
Il codice sorgente mostrato in questa lezione è reperibile qui.
Visualizzazione registrazioni
Una volta inserita una registrazione la ListView della Homepage e quella relativa al tipo di registrazione si popola, mostrandoci Titolo e Autore. Per vedere il resto tappiamo sull’elemento della ListView desiderato per aprire la magica Activity di visualizzazione
Diversamente da quanto mostrato precedentemente ho cercato di mantenere lo stile delle ListView quindi ogni elemento è quadrettato e ha il suo solito pezzetto di vetro e un abbiamo un campo per riga.
L’activity è divisa in 3 TAB:
- Libro (Disco, Fumetto): è quella selezionata al “tap”, ci mostra il contenuto della registrazione
- Prestito: Permette di inserire e mostrare i prestiti relativi a quella registrazione (la copertina era inutile e di difficile implementazione)
- Autore: apre la pagina Wikipedia relativa all’autore
I TAB vengono gestiti da 3 fragment distinti VisAllTab1, VisAllTab2 e VisAllTab3, interrogando un db dove ogni registrazione ha un id possiamo prenderci il lusso di usare lo stesso codice per tutte le tipologie.
Vediamo il layout dell’activity VisualizzaLibri, che si occupa di gestire ActionBar, TAB e pulsanti FAB (file layout/actvivity_visualizza_libri.xml)
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.begeekmyfriend.bereader.VisualizzaLibri"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/appbar_padding_top" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/AppTheme.PopupOverlay"> </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fb_delete" android:src="@mipmap/ic_action_discard" app:fabSize="normal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:layout_marginBottom="16dp" android:layout_marginEnd="10dp" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fb_add" android:src="@mipmap/ic_add_white" app:fabSize="normal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|left" android:layout_marginBottom="16dp" android:layout_marginStart="10dp" /> </android.support.design.widget.CoordinatorLayout>
Il layout ha due Floating Action Button che visualizzeremo dinamicamente a livello di codice (il cestino lo vogliamo solo sul tab Libro e il + solo sul TAB prestiti). Come spiegato nelle lezioni precedenti grazie al CoordinatorLayout e ai Behavior facciamo sparire la Actionbar.
Vediamo il codice sorgente della classe VisualizzaLibri (VisualizzaLibri.java)
package com.begeekmyfriend.bereader; import android.content.Intent; import android.database.Cursor; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TabLayout; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.os.Bundle; import android.view.MenuItem; import android.view.View; public class VisualizzaLibri extends AppCompatActivity { private SectionsPagerAdapter mSectionsPagerAdapter; private ViewPager mViewPager; String id_db; FloatingActionButton fab_del, fb_add; DatabaseBeReader db; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_visualizza_libri); Intent intent = getIntent(); String pkg = getPackageName(); id_db = intent.getStringExtra(pkg + ".ID"); //Recupero quanto passato come argomento all'activity Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); //Pulsante di navigazione clickabile mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); //istazio un oggetto per l'adapeter // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.container); //inizializzo il pager mViewPager.setAdapter(mSectionsPagerAdapter); //associo l'adapter al pager TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); //inizializzo i tab tabLayout.setupWithViewPager(mViewPager); //e gli associo i pager db = new DatabaseBeReader(this); String titolo = recupera_titolo(id_db); getSupportActionBar().setTitle(titolo); fab_del = (FloatingActionButton) findViewById(R.id.fb_delete); fab_del.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { db.open(); db.cancellaById(id_db); //richiamo il metodo di cancellazione del record finish(); //chiudo l'activity } }); fb_add = (FloatingActionButton) findViewById(R.id.fb_add); fb_add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), AggiungiPres.class); //apro una nuova activity String pkg = getPackageName(); //Passo come parametro alla nuova Activity l'id della registrazione intent.putExtra(pkg+"ID_DB", id_db); startActivity(intent); } }); fab_del.show(); fb_add.hide(); tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { mViewPager.setCurrentItem(tab.getPosition()); animateFab(tab.getPosition()); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } }); } public String recupera_titolo(String id_db) { db.open(); Cursor c_tit = db.fetchById(id_db); String titolo = null; if ( c_tit.getCount() > 0) //Dopo aver aperto il db inizializza i componenti { while (c_tit.moveToNext()) { //anche se ho sicuramente un solo recordo mi serve un ciclo titolo = c_tit.getString(c_tit.getColumnIndex(DatabaseBeReader.BeReaderMetaData.TITOLO)); } } db.close(); return titolo; } private void animateFab(int position) { switch (position) { case 0: fab_del.show(); fb_add.hide(); break; case 1: fb_add.show(); fab_del.hide(); break; default: fab_del.hide(); fb_add.hide(); break; } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { // Respond to the action bar's Up/Home button case android.R.id.home: //NavUtils.navigateUpFromSameTask(this); finish(); return true; } return super.onOptionsItemSelected(item); } public class SectionsPagerAdapter extends FragmentPagerAdapter { //classe interna per l'adapter public SectionsPagerAdapter(FragmentManager fm) { //costruttore super(fm); } @Override public Fragment getItem(int position) { //i base alla tab apro un nuovo fragment Fragment frag_tab = null; Bundle args = new Bundle(); switch (position) { case 0: frag_tab = new VisAllTab1(); args.putString("ID", id_db); //passo argomenti al Fragment frag_tab.setArguments(args); //fb_add.hide(); break; case 1: frag_tab = new VisAllTab2(); args.putString("ID", id_db); //passo argomenti al Fragment frag_tab.setArguments(args); //fb_add.show(); break; case 2: frag_tab = new VisAllTab3(); args.putString("ID", id_db); //passo argomenti al Fragment frag_tab.setArguments(args); //fb_add.hide(); break; } return frag_tab; } @Override public int getCount() { //Voglio 3 TAb // Show 3 total pages. return 3; } @Override public CharSequence getPageTitle(int position) { //Titolo dei tab switch (position) { case 0: return getResources().getString(R.string.libro); case 1: return getResources().getString(R.string.prestito); case 2: return getResources().getString(R.string.autore); } return null; } } }
Il compito di nascondere o mostrare il pulsante FAB è di questo listener:
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { mViewPager.setCurrentItem(tab.getPosition()); animateFab(tab.getPosition()); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } });
e di questo metodo:
private void animateFab(int position) { switch (position) { case 0: fab_del.show(); fb_add.hide(); break; case 1: fb_add.show(); fab_del.hide(); break; default: fab_del.hide(); fb_add.hide(); break; } }
Che forniscono un eccitante effetto scomparsa al momento del cambio Tab.
Il Fragment VisAllTab1
Come abbiamo detto il primo Tab è gestito da questo Fragment come sempre vediamo prima il layout (file layout/fragment_vis_all_tab1.xml)
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/content_visualizza" /> </android.support.design.widget.CoordinatorLayout>
Anche qui per pulizia abbiamo diviso il layout in due vediamo il resto (file layout/content_visualizza.xml)
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/paper_tile" android:paddingLeft="10dp" android:paddingRight="10dp" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:id="@+id/ll_tit" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" android:gravity="center" android:orientation="vertical" android:background="@drawable/border_layout"> <TextView android:id="@+id/titolo_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:text="@string/titolo"/> <TextView android:id="@+id/titolo_tv" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:id="@+id/ll_aut" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:gravity="center" android:orientation="vertical" android:background="@drawable/border_layout"> <TextView android:id="@+id/autore_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:text="@string/autore"/> <TextView android:id="@+id/autore_tv" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:id="@+id/ll_for" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:gravity="center" android:orientation="vertical" android:background="@drawable/border_layout"> <TextView android:id="@+id/formato_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:text="@string/formato"/> <TextView android:id="@+id/formato_tv" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:id="@+id/ll_gen" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:gravity="center" android:orientation="vertical" android:background="@drawable/border_layout"> <TextView android:id="@+id/genere_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:text="@string/genere"/> <TextView android:id="@+id/genere_tv" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:id="@+id/ll_pos" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:gravity="center" android:orientation="vertical" android:background="@drawable/border_layout"> <TextView android:id="@+id/posizione_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textStyle="bold" android:text="@string/posizione"/> <TextView android:id="@+id/posizione_tv" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout> </android.support.v4.widget.NestedScrollView>
Abbiamo associato un id a ogni “rettangolo” (il LinearLayout) così da poterlo intercettare per modificare le registrazioni, con l’attributo android:background=”@drawable/border_layout” creiamo l’effetto vetro stondato identico alla ListView.
Il codice della classe VisAllTab1 è molto corposo ed è stato analizzato nelle precedenti lezioni quindi mi limito a riportarlo per completezza (file VisAllTab1.java)
package com.begeekmyfriend.bereader; import android.database.Cursor; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.os.Bundle; import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.DatePicker; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; /** * Created by fabrizio on 17/04/16. */ public class VisAllTab1 extends Fragment { private static final String ARG_SECTION_NUMBER = "section_number"; static DatabaseBeReader db; Cursor c, c_new; static String id_db; static TextView titolo_tv, autore_tv, formato_tv, genere_tv, posizione_tv; //, prestato_tv, prestato_chi_tv, prestato_quando_tv; FloatingActionButton fab_del; LinearLayout ll_tit, ll_aut, ll_for, ll_gen, ll_pos, ll_pres, ll_pres_c, ll_pres_q; public VisAllTab1() { //Inutile costruttore di default } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); View rootView = inflater.inflate(R.layout.fragment_vis_all_tab1, container, false); Bundle args = getArguments(); id_db = args.getString("ID"); //Recuperiamo l'id passatoci dall'Activity //Inizializzo tutti i TetxVew adibiti al contenimento dei dati titolo_tv = (TextView) rootView.findViewById(R.id.titolo_tv); autore_tv = (TextView) rootView.findViewById(R.id.autore_tv); formato_tv = (TextView) rootView.findViewById(R.id.formato_tv); genere_tv = (TextView) rootView.findViewById(R.id.genere_tv); posizione_tv = (TextView) rootView.findViewById(R.id.posizione_tv); db = new DatabaseBeReader(getActivity()); //Istanzio l'oggetto db.open(); //Apro la connesione al db c = db.fetchById(id_db); //Lancio la query By id if ( c.getCount() > 0) //Dopo aver aperto il db inizializza i componenti { while (c.moveToNext()) { //anche se ho sicuramente un solo recordo mi serve un ciclo //scrivo il valore del campo del recordo all'interno della TextView titolo_tv.setText(c.getString(c.getColumnIndex(DatabaseBeReader.BeReaderMetaData.TITOLO))); autore_tv.setText(c.getString(c.getColumnIndex(DatabaseBeReader.BeReaderMetaData.AUTORE))); formato_tv.setText(c.getString(c.getColumnIndex(DatabaseBeReader.BeReaderMetaData.FORMATO))); genere_tv.setText(c.getString(c.getColumnIndex(DatabaseBeReader.BeReaderMetaData.GENERE))); posizione_tv.setText(c.getString(c.getColumnIndex(DatabaseBeReader.BeReaderMetaData.POSIZIONE))); } } // Inizializzo i componenti per la modifica e richiamo metodo creato appositamente ll_tit = (LinearLayout) rootView.findViewById(R.id.ll_tit); ll_tit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { modificaRegistrazioni(0,DatabaseBeReader.BeReaderMetaData.TITOLO, titolo_tv.getText()); } }); ll_aut = (LinearLayout) rootView.findViewById(R.id.ll_aut); ll_aut.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { modificaRegistrazioni(0,DatabaseBeReader.BeReaderMetaData.AUTORE, autore_tv.getText()); } }); ll_for = (LinearLayout) rootView.findViewById(R.id.ll_for); ll_for.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { modificaRegistrazioni(1,DatabaseBeReader.BeReaderMetaData.FORMATO, formato_tv.getText()); } }); ll_gen = (LinearLayout) rootView.findViewById(R.id.ll_gen); ll_gen.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { modificaRegistrazioni(0,DatabaseBeReader.BeReaderMetaData.GENERE, genere_tv.getText()); } }); ll_pos = (LinearLayout) rootView.findViewById(R.id.ll_pos); ll_pos.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { modificaRegistrazioni(0,DatabaseBeReader.BeReaderMetaData.POSIZIONE, posizione_tv.getText()); } }); db.close(); //chiudo la connessione return rootView; } private void modificaRegistrazioni(int tipo, final String campo, CharSequence oldt1) { Bundle args = new Bundle(); FragmentManager fm = getActivity().getSupportFragmentManager(); //Istanzio il fragment manager args.putInt("TIPOL", tipo); //Ci serve per sapere se ci serve o l'EditText o Lo Spinner args.putString("CAMPO", campo); //Campo da modificare args.putCharSequence("STRINGA", oldt1); DialogoModifica dialogo = new DialogoModifica(); //Istanzio l'oggetto della classe del Dialog dialogo.setArguments(args); //Passo gli argomenti dialogo.setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogFragment); //Setto uno stile personalizzato dialogo.show(fm, null); //Apro il Dialog } public static class DialogoModifica extends DialogFragment { String campo; CharSequence oldt1; TextView old_val; ImageButton bottone_mod; int tipo_layout; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Recupero gli argomenti Bundle args = getArguments(); oldt1 = args.getCharSequence("STRINGA"); campo = args.getString("CAMPO"); tipo_layout = args.getInt("TIPOL"); View rootView = null; //In base al tipo di layout decido se mi serve il layout con dell'EditText o lo spinner switch (tipo_layout) { case 0: //EditText rootView = inflater.inflate(R.layout.dialog_modifica, container, false); TextView label = (TextView) rootView.findViewById(R.id.label_modifica); label.setText("Modifica ".concat(campo.toLowerCase())); old_val = (TextView) rootView.findViewById(R.id.et_oval); old_val.setText(oldt1); final EditText new_val = (EditText) rootView.findViewById(R.id.ed_nval); new_val.setHint(oldt1); //associo un Hint (suggerimento) bottone_mod = (ImageButton) rootView.findViewById(R.id.bottone_modifica); bottone_mod.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { db.open(); db.editById(id_db, campo, new_val.getText().toString()); //Modifico la registrazione db.close(); //Mi preparo ad aggiornare il layput dopo la modifica switch (campo) { case DatabaseBeReader.BeReaderMetaData.TITOLO: titolo_tv.setText(new_val.getText().toString()); break; case DatabaseBeReader.BeReaderMetaData.AUTORE: autore_tv.setText(new_val.getText().toString()); break; case DatabaseBeReader.BeReaderMetaData.GENERE: genere_tv.setText(new_val.getText().toString()); break; case DatabaseBeReader.BeReaderMetaData.POSIZIONE: posizione_tv.setText(new_val.getText().toString()); break; } getDialog().dismiss(); //Chiudo il Dialog } }); return rootView; case 1: //Spinner rootView = inflater.inflate(R.layout.dialog_modifica2, container, false); label = (TextView) rootView.findViewById(R.id.label_modifica); label.setText("Modifica ".concat(campo.toLowerCase())); old_val = (TextView) rootView.findViewById(R.id.et_oval); old_val.setText(oldt1); final Spinner sp_nval = (Spinner) rootView.findViewById(R.id.sp_nval); ArrayAdapter aa = null; //In base al campo setto l'ArrayAdapter e lo spinner con i Giusti valori switch (campo) { case DatabaseBeReader.BeReaderMetaData.FORMATO: //Anche il formato è diverso if (getActivity().getClass() == VisualizzaDischi.class) { aa = ArrayAdapter.createFromResource(getActivity(), R.array.ar_formato_dischi, R.layout.spinner); } else { aa = ArrayAdapter.createFromResource(getActivity(), R.array.ar_formato_libri, R.layout.spinner); } break; } sp_nval.setAdapter(aa); bottone_mod = (ImageButton) rootView.findViewById(R.id.bottone_modifica); bottone_mod.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { db.open(); db.editById(id_db, campo, sp_nval.getSelectedItem().toString()); //Modifico la registrazione db.close(); //Aggiornamenti del layout post modifica switch (campo) { case DatabaseBeReader.BeReaderMetaData.FORMATO: formato_tv.setText(sp_nval.getSelectedItem().toString()); break; default: break; } getDialog().dismiss(); //Chiudo il Dialog } }); return rootView; default : //Inutile ma il compilatore non lo sa, se non lo metti da errore di compilazione return rootView; } } } }
Il fragment VisAllTab2
Questo fragment (mai analizzato nemmeno parzialmente) permette l’inserimento e la visualizzzazione delle registrazioni relative ai prestiti e ha il seguente aspetto:
Come si nota il FAB cancella è sparito (non mi piaceva avere due TAB nello stesso layout) e al suo posto abbiamo un ottimo + (l’effetto scomparsa è più marcato se il pulsante è dalla parte opposta). Il codice Java e il layout sono molto simili a i Fragment richiamati dal Navigation Drawer, quindi vi mostro solo la porzione di codice relativo al “tap” sulla ListView
presLV.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Snackbar.make(view, "Cancella", Snackbar.LENGTH_LONG). setAction("CANCELLA", new View.OnClickListener() { @Override public void onClick(View view) { db.open(); db.cancellaPresById(c.getString(c.getColumnIndex(DatabaseBeReader.BeReaderPresMetaData.ID))); c = db.fetchPresById(id_db); cur_resume = new SimpleCursorAdapter( getActivity(), R.layout.cursor_layout, c, new String[] {DatabaseBeReader.BeReaderPresMetaData.PRESTATO_CHI, DatabaseBeReader.BeReaderPresMetaData.PRESTATO_QUANDO}, new int[]{R.id.raw1 , R.id.raw2}, 0); presLV.setAdapter(cur_resume); db.close(); } }). show(); } });
Questo codice ci mostra un nuovo componente, lo SnackBar cioè un messaggio che appare in basso sullo schermo.
Anche qui i componenti sono Coordinati infatti il pulsante FAB sale per far posto alla SnackBar (eccitazioneeee). Abbiamo munito il messaggio di pulsante quindi ci basta fare tap per cancellare la registrazione. Le specifiche del Material Design vietano l’inserimento di più di un pulsante all’interno della SnackBar anche se è possibile a livello di codice (nessuno dovrebbe arrestarvi, ma forse la vostra app potrebbe essere penalizzata sul Play Store).
Inserire un prestito
Per l’inserimento del prestito abbiamo creato un’Activity molto simile a quella di inserimento generico ma con un nuovo componente il DatePicker.
Ecco il content del layour (file content_aggiungi_pres.xml)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".AggiungiPres" tools:showIn="@layout/activity_aggiungi_pres"> <ScrollView android:id="@+id/sv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="50dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/prestato_chi"/> <EditText android:id="@+id/et_prestato_chi" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/prestato_quando"/> <DatePicker android:id="@+id/dp_quando" android:layout_width="match_parent" android:layout_height="wrap_content" android:calendarViewShown="false" android:datePickerMode="spinner"/> </LinearLayout> </ScrollView> <ImageButton android:id="@+id/pres_salva" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:text="@string/salva" android:src="@mipmap/ic_action_save"/> </RelativeLayout>
La nostra Activity ha quindi questo aspetto:
La gestione del DatePicker è molto semplice, vediamo il codice Java (file aggiungiPres.java)
package com.begeekmyfriend.bereader; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.DatePicker; import android.widget.EditText; import android.widget.ImageButton; public class AggiungiPres extends Activity { //Defnisco istanze degli oggetti EditText et_prestato_chi; //, et_prestato_quando; ImageButton button_salva; DatePicker dp_prestato_i, dp_prestato_f; DatabaseBeReader db; String id_db; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_aggiungi_pres); Intent intent = getIntent(); String pkg = getPackageName(); id_db = intent.getStringExtra(pkg+"ID_DB"); //Recupero quanto passato come argomento all'activity et_prestato_chi = (EditText) findViewById(R.id.et_prestato_chi); dp_prestato_i = (DatePicker) findViewById(R.id.dp_quando); button_salva = (ImageButton) findViewById(R.id.pres_salva); button_salva.setOnClickListener(new View.OnClickListener() { //Classe anonima per il clicj dell'image button @Override public void onClick(View v) { salva(); //Richiamo metodo per il salvataggio } }); } public void salva() { db = new DatabaseBeReader(this); //Denisco istanza dell'oggetto db e richiamo il costruttore db.open(); //Apro il db String mese_i = Utility.trasforma_mese(dp_prestato_i.getMonth()); //richiamo metodo di utilità che trasforma il numero del mese in caratteri String pres_i = dp_prestato_i.getDayOfMonth() + "/" + mese_i + "/" + dp_prestato_i.getYear(); //registro la data per intero db.inserisci_pres(id_db, et_prestato_chi.getText().toString(), pres_i, ""); db.close(); //Chiudo il db finish(); //chiudo il dialog } }
Ci sono 3 metodi che permetto rispettivamente di recuperare:
- numero del giorno: getDayOfMonth()
- numero del mese -1: getMonth() (ebbene si in informatica si conta da zero quindi gennaio è il mese 0, febbraio il mese 1 e così via)
- anno: getYear();
Il Fragment VisAllTab3
Tale Fragment è stato creato nella lezione 11 quindi lo tralascio (non ha subito modifiche è stato solo rinominato)
Prossima lezione
Nella prossima lezione vedremo come creare una query SQL complessa per incrociare il dati delle due tabelle, così da poter gestire al meglio la voce di Menu prestiti (nei sorgenti troverete una bozza)
Originariamente pubblicato su Be Geek My Friend