• Programmazione Android
  • CORSI ONLINE
  • Web Agency

Logo

Corsi di programmazione web e mobile online
Navigation
  • Home
  • CORSI ONLINE
  • Tutorial Pratici
  • GUIDE COMPLETE
    • Corso completo di C
    • Corso videogame con Cocos2d
    • Programmazione Cocoa Touch
  • Sezioni
    • Libri e manuali
    • Tips & Tricks
    • Risorse utili
    • Strumenti di Sviluppo
    • Materiale OpenSource
    • Framework
    • Guide Teoriche
    • Guide varie
    • Grafica e Design
    • iPad
    • News
    • Video Tutorial
    • Windows Phone
  • Pubblicità
  • About
    • Chi siamo
    • Pubblicazioni
    • Collabora
    • Sostieni devAPP

Bottom Sheets in Android

By Giuseppe Maggi | on 27 Giugno 2017 | 0 Comment
Android
Android Bottom Sheets Tutorial

Con il Material Design, si sa, le interfacce Android (e di tutte le tecnologie legate a Google) hanno acquistato grande dinamicità. Uno dei pattern grafici che si è affermato si basa su “fogli scorrevoli” in grado di spuntare dal fondo della schermo (occupandolo, nel senso della larghezza, integralmente o in parte) per mostrare sezioni accessorie dell’interfaccia. Stiamo parlando dei cosiddetti Bottom Sheets ed in questo tutorial ne vedremo un esempio di applicazione nelle app Android il cui codice è disponibile qui.

Tipologie di Bottom Sheet

Tanto per iniziare, osserviamo le Google Maps che – tra gli altri – hanno fatto ottimo uso dei Bottom Sheet. Capita spesso di consultare una mappa e ricevere informazioni accessorie tramite un pannello che scorre dal fondo:

bottom_sheets_android_material_design_google_img_01

Questo è proprio un Bottom Sheet. L’avremo notato anche nella versione desktop (non dimentichiamo che il Material Design non coinvolge solo l’ambito mobile) ma questa volta in versione “persistente” ossia permanente:

bottom_sheets_android_material_design_google_img_02

Questi primi esempi rappresentano le due tipologie principali di Bottom Sheet:

  • modali, dedicati per lo più al mobile, servono per aggiungere temporaneamente un altro pò di superficie dove far scorrere ulteriori contenuti. Hanno generalmente un livello di di elevazione superiore all’interfaccia dell’app e vengono molto spesso utilizzati come sostituti ideali per menu e finestre di dialogo;
  • persistenti, molto presenti in ambienti desktop, sono pannelli aggiuntivi, fissi, che mostrano ulteriori contenuti. Considerando che vengono molto usati in ambiti dove le condizioni di spazio non sono così stringenti si può spesso rinunciare al loro utilizzo.

L’esempio

Nel nostro esempio, ne sperimenteremo la realizzazione sottolineandone i fattori principali. Nell’interfaccia vedremo una lista di CardView, ognuna delle quali riguardante una città italiana.

bottom_sheets_android_material_design_google_img_03

Immaginiamo di volere che al click di una di queste si apra una WebView con il caricamento della pagina di Wikipedia riguardante il centro abitato in questione: per sfruttare al meglio lo spazio a disposizione inseriremo la WebView proprio all’interno di un Bottom Sheet che potrà essere esteso o ridotto manualmente dall’utente.

bottom_sheets_android_material_design_google_img_05

Il layout

La struttura del layout principale vede:

  • una RecyclerView che fornisce una versione più moderna e ottimizzata della ListView con la quale mostreremo l’elenco di città selezionabili;
  • una NestedScrollView alla quale assegniamo un “comportamento” (behavior come si usa dire nel Material Design) da Bottom Sheet e lo faremo integrando il seguente attributo:
    <android.support.v4.widget.NestedScrollView
        ...
        ...
        app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

Questo il testo completo del layout dell’Activity:

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerview"/>

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="550dp"
    app:behavior_peekHeight="120dp"
    android:id="@+id/bottom_sheet"
    android:elevation="4dp"
    android:minHeight="120dp"
    app:behavior_hideable="true"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:orientation="vertical">

        <ProgressBar
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_gravity="center"
            android:indeterminate="true"
            android:padding="15dp"
            android:visibility="gone"
            android:id="@+id/spinner"/>
        <WebView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/web"/>

    </LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

Si notino altri elementi all’interno del nodo NestedScrollView, anch’essi relativi al behavior da Bottom Sheet:

  • elevation che solleva la Bottom Sheet rispetto all’interfaccia utente;
  • behavior_peekHeight che imposta la dimensione del Bottom Sheet quando viene chiuso (collapsed, come spiegheremo a breve)
  • behavior_hideable permette, se valorizzato a true, di nascondere il componente quando viene trascinato manualmente verso il basso.

La MainActivity

Per gestire il Bottom Sheet dal codice Java dobbiamo innanzitutto raccogliere un riferimento all’oggetto che ne rappresenta il comportamento (nel nostro caso la NestedScrollView):

bottomSheet = findViewById(R.id.bottom_sheet);
mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);

e tramite questo arrivare ad un BottomSheetBehavior che ne gestirà direttamente le funzionalità. I Bottom Sheet sono anche provvisti di un apposito listener in grado di gestirne i cambiamenti di stato:

mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(View bottomSheet, int newState) {
                
               switch(newState)
                {
                    case BottomSheetBehavior.STATE_COLLAPSED:
                        ...
                        ...
                        break;
                    case BottomSheetBehavior.STATE_DRAGGING:
                        ...
                        ...
                        break;
                    case BottomSheetBehavior.STATE_EXPANDED:
                        ...
                        ...
                        break;
                    case BottomSheetBehavior.STATE_HIDDEN:
                        ...
                        ...
                        break;
                    case BottomSheetBehavior.STATE_SETTLING:
                        ...
                        ...
                }

            }

            @Override
            public void onSlide(View bottomSheet, float slideOffset) {

            }
        });

In base alle costanti indicate nel metodo onStateChanged possiamo vedere i principali stati di un BottomSheet:

  • COLLAPSED: il componente è chiuso;
  • EXPANDED: attualmente è totalmente aperto;
  • HIDDEN: non è più visibile;
  • DRAGGING: è in trascinamento.

Ogni volta che eseguiremo il click su una CardView, riporteremo il BottomSheet in posizione COLLAPSED e renderemo di nuovo visibile la ProgressBar che attenderà il caricamento della nuova pagina di Wikipedia nella WebView.

Quello che segue è il codice dell’Activity:

public class MainActivity extends AppCompatActivity implements AdapterView.OnClickListener{

    private BottomSheetBehavior bottomSheetBehavior;
    private View bottomSheet;
    private RecyclerView recyclerView;
    private WebView webView;
    private ProgressBar spinner;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView= (RecyclerView) findViewById(R.id.recyclerview);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        CityAdapter adapter=new CityAdapter(this);
        recyclerView.setAdapter(adapter);
        webView= (WebView) findViewById(R.id.web);
        spinner= (ProgressBar) findViewById(R.id.spinner);
        bottomSheet = findViewById( R.id.main_content ).findViewById(R.id.bottom_sheet);

        bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
    }


    @Override
    public void onClick(View view) {
        TextView citta= (TextView) view.findViewById(R.id.title);
        String c= citta.getText().toString();
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);

        webView.setWebViewClient(new WebViewClient()
        {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                spinner.setVisibility(View.VISIBLE);
                webView.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                spinner.setVisibility(View.GONE);
                webView.setVisibility(View.VISIBLE);
            }
        }
        );

        webView.loadUrl("https://it.wikipedia.org/wiki/"+c);
    }
}

Nel nostro caso, non gestiremo il listener ma al click su un elemento della RecyclerView apriremo il BottomSheet nello stato COLLAPSED e faremo apparire la ProgressBar che ruoterà fino al completo caricamento dei contenuti nella WebView:

bottom_sheets_android_material_design_google_img_04

I dati relativi alle città provengono da una lista riempita staticamente all’interno dell’Adapter: questo componente non riguarda invece il funzionamento del Bottom Sheet. Di seguito il codice dell’Adapter:

public class CityAdapter extends RecyclerView.Adapter<CityAdapter.CustomViewHolder> {

    private View.OnClickListener listener;
    private Context context;

    private String[] city_list=
            new String[]
                    {"Roma",
                     "Milano",
                     "Torino",
                     "Napoli",
                     "Firenze",
                     "Genova",
                     "Palermo",
                     "Trieste",
                     "Cagliari",
                     "Ancona",
                     "Bari",
                     "Perugia",
                     "Trento",
                     "Venezia",
                     "Campobasso"};

    @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, null);
        CustomViewHolder viewHolder = new CustomViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(CustomViewHolder holder, int position) {
        String city=city_list[position];
        holder.textView.setText(city);
        holder.imageView.setImageResource(context.getResources().getIdentifier(city.toLowerCase(), "drawable", context.getPackageName()));
    }

    CityAdapter(View.OnClickListener listener)
    {
        this.listener=listener;
        context= (Context) listener;
    }

    @Override
    public int getItemCount() {
        return city_list.length;
    }

    class CustomViewHolder extends RecyclerView.ViewHolder {
        protected TextView textView;
        protected CircleImageView imageView;

        public CustomViewHolder(View view) {
            super(view);
            view.setOnClickListener(listener);
            this.textView = (TextView) view.findViewById(R.id.title);
            this.imageView= (CircleImageView) view.findViewById(R.id.image);
        }
    }
}

 

Conclusioni

La classe BottomSheetBehavior che abbiamo visto in questo esempio è un’altra dimostrazione di come pattern visuali cui veniamo abituati velocemente come utenti Android possano essere messi in pratica agevolmente anche nelle nostre app. In fin dei conti, l’intero meccanismo viene messo in atto dall’assegnazione di un behavior ad un elemento incluso in un CoordinatorLayout, tutto il resto poi è una normale gestione di listener ed eventi. La semplice applicabilità di questi elementi non deve però indurre ad un loro abuso: come spiega la documentazione ufficiale di Google inerente il Material Design infatti, i BottomSheet dovrebbero essere impiegati laddove sia necessario espandere lo superficie a disposizione dell’interfaccia e non solo come un puro vezzo estetico.

Share this story:
  • tweet

Tags: androidbottom sheetsdesign user interfacegoogleMaterial DesignpatternTutorial Praticiuser interface

Recent Posts

  • Parte il percorso programmatori iOS in Swift su devACADEMY.it

    20 Dicembre 2017 - 0 Comment
  • Android, crittografare dati velocemente con Encryption

    24 Settembre 2018 - 0 Comment
  • Sql2o, accesso immediato ai database tramite Java

    3 Settembre 2018 - 0 Comment
  • Okio, libreria per ottimizzare l’input/output in Java

    27 Agosto 2018 - 0 Comment

Related Posts

  • IntelliJ IDEA: IDE per programmare in Java e Kotlin

    25 Luglio 2018 - 0 Comment
  • Android: usare Connect Pattern

    10 Luglio 2018 - 0 Comment
  • Android: il metodo findViewById() non richiede più il cast

    21 Giugno 2018 - 0 Comment

Author Description

No Responses to “Bottom Sheets in Android”

Leave a Reply

Your email address will not be published. Required fields are marked *


*
*

Corso online di programmazione android e java

SEZIONI

  • Android
  • Comunicazioni
  • Contest
  • Corsi ed Eventi
  • Corso completo di C
  • Corso programmazione videogiochi
  • Framework
  • Grafica e Design
  • Guida rapida alla programmazione Cocoa Touch
  • Guide Teoriche
  • Guide varie
  • iPad
  • Le nostre applicazioni
  • Libri e manuali
  • Materiale OpenSource
  • News
  • Pillole di C++
  • Progetti completi
  • Risorse utili
  • Strumenti di Sviluppo
  • Swift
  • Tips & Tricks
  • Tutorial Pratici
  • Video Tutorial
  • Windows Phone

Siti Amici

  • Adrirobot
  • Allmobileworld
  • Apple Notizie
  • Apple Tribù
  • Avvocato360
  • Blog informatico 360°
  • bubi devs
  • fotogriPhone
  • GiovaTech
  • iApp-Mac
  • iOS Developer Program
  • iPodMania
  • MelaRumors
  • Meritocracy
  • SoloTablet
  • TecnoUser
  • Privacy & Cookie Policy
©2009-2018 devAPP - All Rights Reserved | Contattaci
devAPP.it è un progetto di DEVAPP S.R.L. - Web & Mobile Agency di Torino
Str. Volpiano, 54 - 10040 Leini (TO) - C.F. e P.IVA 11263180017 - REA TO1199665 - Cap. Soc. € 10.000,00 i.v.

devACADEMY.it

Vuoi imparare a programmare?

Iscriviti e accedi a TUTTI i corsi con un’unica iscrizione.
Oltre 70 corsi e migliaia di videolezioni online e in italiano a tua disposizione.

ISCRIVITI SUBITO