corso programmazione android lezione 13

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

 

corso programmazione android lezione 13

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:

corso programmazionea ndroid lezione 13

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.

corso programmazione android lezione 13

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:

 

corso programmazione android lezione 13

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

Autore dell'articolo: fabrizio

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *