Dopo aver classificato i principali layout in base a tipologia e finalità, passiamo all'aspetto pratico, il vero e proprio markup XML necessario a definirli.
Elementi comuni nei layout
Prima di passare agli esempi definiamo alcuni elementi che accomunano le sintassi di tutti i layout. Innanzitutto, gli attributi XML utilizzati per la maggior parte proverranno da un namespace avente URI http://schemas.android.com/apk/res/android. Per questo motivo quando definiremo layout in un progetto Android il nodo root che conterrà tutti gli elementi mostrerà al suo interno la dichiarazione
xmlns:android="http://schemas.android.com/apk/res/android"
e darà senso al prefisso android: che verrà usato per tutti gli attributi nel file.
Secondo aspetto comune non solo ai layout ma anche a tutti gli elementi in essi contenuti, la presenza obbligatoria di due attributi: layout_width e layout_height, che definiscono la capacità dell'elemento di estendersi, rispettivamente, in larghezza (width) o altezza (height). Il loro valore può essere una dimensione, espressa in dp, come già spiegato, o una costante da scegliere tra:
- wrap_content: l'elemento sarà alto o largo a sufficienza per includere il suo contenuto;
- match_parent: l'elemento si estenderà in altezza o in larghezza fino a toccare il suo contenitore.
Quando si andrà ad impostare layout_heigth (o layout_width) l'IDE suggerirà un terzo valore possibile, fill_parent. Questo rappresenta un sinonimo di match_parent ma non va usato in quanto ormai deprecato.
Nel prosieguo di questo capitolo, verrà presentata la sintassi di base dei principali layout. Gli elementi posizionati all'interno dei layout potranno essere altri layout annidati o semplici controlli utente, termine con cui si indicano tutti i controlli per interfacce utente. Nel terzo esempio faranno la loro comparsa TextView e Button, molto comuni nelle UI Android. Nei prossimi capitoli ci sarà spazio per un maggior approfondimento sui controlli utente.
Sintassi dei layout
Il LinearLayout riceve con l'attributo orientation la sua connotazione principale. Con esso si dichiara in quale senso verranno disposti gli elementi, orizzontalmente (il default) o verticalmente.
Un esempio:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
. . .
. . .
</LinearLayout>
Il TableLayout viene specificato mediante due tag: TableLayout e TableRow.
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TableRow
android:layout_width="wrap_content"
android:layout_height="match_parent">
. . .
. . .
</TableRow>
. . .
. . .
</TableLayout>
TableLayout rappresenta la tabella nel suo complesso mentre ogni nodo TableRow contiene tutti gli elementi di una riga. Il concetto di colonna viene reso in automatico, ogni elemento in un TableRow costituisce una colonna.
Il RelativeLayout sfrutta gli attributi per definire posizionamenti. Sono molti ma piuttosto intuitivi.
A scopo di orientamento, segue una tabella riassuntiva che ne raggruppa le diverse categorie in base alla finalità. Il tipo di valore assegnato a questi attributi può essere booleano (true o false) o l'id di un elemento appartenente al layout.
layout_alignParentTop
layout_alignParentBottom layout_alignParentLeft layout_alignParentRight |
Allineamento con il contenitore: attributi che definiscono se l'elemento deve allinearsi ad uno dei bordi del proprio contenitore. Il valore di questo attributo è di tipo booleano |
layout_alignTop
layout_alignBottom layout_alignLeft layout_alignRight |
Allineamento con altro elemento: attributi che definiscono se l'elemento deve allinearsi ad uno dei bordi di un altro elemento del layout. Il valore di questo attributo sarà l'id dell'elemento con cui allinearsi |
layout_above
layout_below layout_toLeftOf layout_toRightOf |
Posizionamento relativo ad un altro elemento: indicano se l'elemento si trova, rispettivamente, sopra, sotto, a sinistra o a destra del componente il cui id è il valore dell'attributo |
layout_centerHorizontal
layout_centerVertical layout_centerInParent |
Centramento: rispettivamente rappresentano se l'elemento deve essere centrato orizzontalmente, verticalmente o in entrambe le direzioni. Il valore è booleano. |
Il frammento di XML che segue mostra un esempio di RelativeLayout con una TextView collocata in alto a sinistra ed un Button in basso al centro:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:text="Esempio di Relative Layout"/>
<Button
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Clicca qui!"/>
</RelativeLayout>
Il ConstraintLayout è il più moderno tra quelli che Android mette a disposizione e si ispira alla flessibilità del RelativeLayout ma con la mission di rendere l'interfaccia utente più responsive possibile evitando al massimo l'annidamento di layout. Il ConstraintLayout è stato proposto in una fase in cui Android Studio era già estremamente maturo e ottimizzato tanto che è totalmente utilizzabile in modalità visuale nell'editor grafico. Layout di questo genere potranno essere perciò preparati con i tool drag-and-drop messi a disposizione per poi, eventualmente, passare nella modalità dichiarativa agendo direttamente sul XML.
Quello che segue è uno stralcio testuale di un layout di tipo Constraint realizzato con editor visuale:
<androidx.constraintlayout.widget.ConstraintLayout
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">
...
...
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginLeft="48dp"
android:layout_marginTop="88dp"
android:text="In alto a SX"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="268dp"
android:layout_marginLeft="268dp"
android:text="Al centro a DX"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.499" />
...
...
</androidx.constraintlayout.widget.ConstraintLayout>