Durante lo sviluppo di un'app che si connetteva ad un servizio remoto, ho avuto la necessità di visualizzare un elemento che indicasse all'utente l'attività in background che il dispositivo stava effettuando.
All'inizio ho optato per un ProgressDialog. E' una buona opzione, ma nel caso siano presenti delle animazioni a seguito di un invio, il dialog "blocca" la visualizzazione delle stesse e risulta antiestetico.
Ho quindi optato per un sistema meno "invasivo": una barra orizzontale per segnalare il lavoro in background.
L'oggetto ProgressBar è semplice da implementare, lo è meno l'integrazione con una ActionBar personalizzata e "importata" nel layout tramite un'inclusione, come in questo esempio:
1
2
3
4
5
6
7
8
9
| <android.support.constraint.ConstraintLayout
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"
tools:context="it.example.test_progressbar.MainActivity">
<include layout="@layout/toolbar"/>
|
Impostazioni di base ed elementi necessari
Dopo aver creato un nuovo progetto "base" con una Activity vuota, per implementare la ProgressBar sono necessari i seguenti file (da creare o modificare):
- activity_main.xml
- toolbar.xml
- AndroidManifest.xml
- styles.xml
- MainActivity.java
Modifiche XML
Partiamo dalle modifiche al design XML, che poi saranno le più "corpose".
AndroidManifest.xml
Il problema iniziale da affrontare è che la struttura "base" creata da Android Studio inserisce una ActionBar "basilare" direttamente dall'AndroidManifest attraverso questa voce:
1
2
3
| <application
...
android:theme="@style/AppTheme">
|
Per eliminare l'ActionBar, bisogna caricare specificare queste righe nel file styles.xml:
1
2
3
4
| <style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
|
rimuovere la voce incriminata e sostituirla con questa:
1
2
3
| <application
...
android:theme="@style/AppTheme.NoActionBar">
|
activity_main.xml
L'XML dell'Activity principale richiede una sola modifica, l'aggiunta della toolbar contenuta nel file separato.
Basta aggiungere, sotto all'apertura del tag del ConstraintLayout inserito dal sistema, di questa riga:
1
| <include layout="@layout/toolbar"/>
|
toolbar.xml
La toolbar di norma viene innestata all'interno di un CoordinatorLayout, che verrà mantenuto.
Il codice di partenza è questo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| <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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="it.tortellinux.diceroller.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
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:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:id="@+id/fragment_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior"
>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
|
Per gestire correttamente la ProgressBar vanno applicate alcune modifiche sostanziali.
Per prima cosa, va rimosso quello che Android "presenta" sotto la Toolbar, cioè un piccolo margine e l'ombra.
Questo perché la ProgressBar verrà visualizzata "sotto" l'ombra e l'effetto sarà... inguardabile.
Bisogna quindi impostare l'elevation ed il margine inferiore a 0dp:
1
2
3
4
5
| <android.support.design.widget.AppBarLayout
...
app:elevation="0dp"
android:layout_marginBottom="0dp"
/>
|
Poi è necessario aggiungere un FrameLayout che conterrà la ProgressBar. La rappresentazione "base" della ProgressBar utilizza un bordo superiore ed uno, più piccolo, inferiore.
Questi verranno eliminati inserendo un altezza di 3dp al frame ed impostando un margine negativo (sì, si può) alla ProgressBar, oltre ad un'altezza fissa.
E' necessario, infine, impostare questo comportamento al frame:
1
2
3
4
| <FrameLayout
...
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
|
Questo impedisce alla Toolbar di "coprire" la ProgressBar.
Questo è il codice finale:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| <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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="it.tortellinux.test_progressbar.MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="3dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<ProgressBar
android:id="@+id/progress_spinner"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="7dp"
android:layout_gravity="top"
android:layout_marginTop="-3dp"
android:indeterminate="true"
android:visibility="visible"
/>
</FrameLayout>
<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay"
app:elevation="0dp"
android:layout_marginBottom="0dp">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"
/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
|
MainActivity.java
Per l'implementazione della ProgressBar bastano le modifiche all'XML indicate qui sopra, solo che c'è bisogno di un sistema per renderla visibile o farla sparire.
Dopo aver recuperato l'oggetto attraverso la funzione findViewById, per impostare la visibilità della ProgressBar si utilizzano due semplici comandi.
Per visualizzarla:
1
| progressBar.setVisibility(View.VISIBLE);
|
Per farla sparire:
1
| progressBar.setVisibility(View.GONE);
|
L'effetto finale
Completati i vari passaggi, si ottiene questo effetto: