Un layout definisce la struttura per un’interfaccia utente nella tua app, ad esempio in un’activity . Tutti gli elementi nel layout vengono creati utilizzando una gerarchia di View e ViewGroup oggetti. A View solitamente disegna qualcosa che l’utente può vedere e con cui interagire. Mentre a ViewGroup è un contenitore invisibile che definisce la struttura del layout per View e altri ViewGroup oggetti, come mostrato nella figura 1.

Figura 1. Illustrazione di una gerarchia di visualizzazione, che definisce un layout dell’interfaccia utente
Gli View oggetti sono generalmente chiamati “widget” e possono essere una delle tante sottoclassi, come Button o TextView. Gli ViewGroup oggetti sono generalmente chiamati “layout” e possono essere uno dei tanti tipi che forniscono una diversa struttura di layout, come LinearLayout o ConstraintLayout .
Puoi dichiarare un layout in due modi:
- Dichiarare gli elementi dell’interfaccia utente in XML . Android fornisce un semplice vocabolario XML che corrisponde alle classi e alle sottoclassi View, come quelle per widget e layout.
Puoi anche utilizzare l’ Editor layout di Android Studio per creare il tuo layout XML utilizzando un’interfaccia drag-and-drop.
- Istanziare gli elementi del layout in fase di esecuzione . La tua app può creare oggetti View e ViewGroup (e manipolarne le proprietà) a livello di codice.
Dichiarare la tua interfaccia utente in XML ti consente di separare la presentazione della tua app dal codice che ne controlla il comportamento. L’utilizzo di file XML semplifica inoltre la fornitura di layout diversi per diverse dimensioni e orientamenti dello schermo (discusso ulteriormente in Supporto di dimensioni diverse dello schermo ).
Il framework Android ti offre la flessibilità di utilizzare uno o entrambi questi metodi per creare l’interfaccia utente della tua app. Ad esempio, puoi dichiarare i layout predefiniti della tua app in XML e quindi modificare il layout in fase di esecuzione.
Suggerimento: per eseguire il debug del layout in fase di esecuzione, utilizzare lo strumento Layout Inspector .
Scrivi l’XML
Utilizzando il vocabolario XML di Android, puoi progettare rapidamente layout dell’interfaccia utente e gli elementi dello schermo che contengono, nello stesso modo in cui crei pagine web in HTML, con una serie di elementi nidificati.
Ogni file di layout deve contenere esattamente un elemento radice, che deve essere un oggetto View o ViewGroup. Dopo aver definito l’elemento radice, è possibile aggiungere ulteriori oggetti di layout o widget come elementi figlio per creare gradualmente una gerarchia di visualizzazione che definisce il layout. Ad esempio, ecco un layout XML che utilizza una verticale LinearLayout per contenere un TextView e a Button:
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:orientation=”vertical” >
<TextView android:id=”@+id/text”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Hello, I am a TextView” />
<Button android:id=”@+id/button”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Hello, I am a Button” />
</LinearLayout>
Dopo aver dichiarato il layout in XML, salva il file con l’ .xml estensione, nella res/layout/ directory del tuo progetto Android , in modo che venga compilato correttamente.
Ulteriori informazioni sulla sintassi per un file XML di layout sono disponibili nel documento Risorse di layout .
Carica la risorsa XML
Quando compili la tua app, ogni file di layout XML viene compilato in una View risorsa. È necessario caricare la risorsa di layout dal codice dell’app, nell’implementazione del Activity.onCreate() callback. Farlo chiamando setContentView(), passandogli il riferimento alla vostra risorsa di layout in forma di: . Ad esempio, se il layout XML viene salvato come , lo caricherai per la tua attività in questo modo: R.layout.layout_file_namemain_layout.xml
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
Il onCreate()metodo di callback nella tua attività viene chiamato dal framework Android quando la tua attività viene avviata (vedi la discussione sui cicli di vita, nel documento sulle attività ).
Attributi
Ogni oggetto View e ViewGroup supporta la propria varietà di attributi XML. Alcuni attributi sono specifici di un oggetto View (ad esempio, TextView supporta l’ textSize attributo), ma questi attributi vengono ereditati anche da qualsiasi oggetto View che può estendere questa classe. Alcuni sono comuni a tutti gli oggetti View, perché sono ereditati dalla classe View radice (come l’ id attributo). Inoltre, altri attributi sono considerati “parametri di layout”, ovvero attributi che descrivono determinati orientamenti di layout dell’oggetto View, come definito dall’oggetto ViewGroup principale di tale oggetto.
ID
Qualsiasi oggetto View può avere un ID intero associato ad esso, per identificare in modo univoco la View all’interno dell’albero. Quando l’app viene compilata, questo ID viene indicato come un numero intero, ma l’ID viene generalmente assegnato nel file XML di layout come stringa, id nell’attributo. Questo è un attributo XML comune a tutti gli oggetti View (definito dalla View classe) e lo userai molto spesso. La sintassi per un ID, all’interno di un tag XML è:
android:id=”@+id/my_button”
Il simbolo di at (@) all’inizio della stringa indica che il parser XML deve analizzare ed espandere il resto della stringa ID e identificarlo come risorsa ID. Il simbolo più (+) significa che questo è un nuovo nome di risorsa che deve essere creato e aggiunto alle nostre risorse (nel R.java file). Esistono numerose altre risorse ID offerte dal framework Android. Quando si fa riferimento a un ID risorsa Android, non è necessario il simbolo più, ma è necessario aggiungere lo android spazio dei nomi del pacchetto, in questo modo:
android:id=”@android:id/empty”
Con lo android spazio dei nomi del pacchetto in posizione, ora stiamo facendo riferimento a un ID dalla android.R classe delle risorse, piuttosto che dalla classe delle risorse locali.
Per creare visualizzazioni e farvi riferimento dall’app, uno schema comune è:
- Definisci una vista / widget nel file di layout e assegnagli un ID univoco:
<Button android:id=”@+id/my_button”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/my_button_text”/>
- Quindi creare un’istanza dell’oggetto vista e acquisirla dal layout (in genere nel onCreate() metodo):
Button myButton = (Button) findViewById(R.id.my_button);
La definizione degli ID per gli oggetti di visualizzazione è importante quando si crea un file RelativeLayout. In un layout relativo, le viste di pari livello possono definire il layout relativo a un’altra vista di pari livello, a cui fa riferimento l’ID univoco.
Un ID non deve essere univoco in tutto l’albero, ma dovrebbe essere univoco all’interno della parte dell’albero che stai cercando (che spesso può essere l’intero albero, quindi è meglio essere completamente unico quando possibile).
Nota: con Android Studio 3.6 e versioni successive, la funzionalità di associazione delle viste può sostituire le findViewById()chiamate e fornisce l’indipendenza dai tipi in fase di compilazione per il codice che interagisce con le viste. Prendi in considerazione l’utilizzo dell’associazione della vista anziché findViewById().
Parametri di layout
Gli attributi di layout XML denominati definiscono i parametri di layout per la vista appropriati per il ViewGroup in cui risiede.layout_something
Ogni classe ViewGroup implementa una classe nidificata che si estende ViewGroup.LayoutParams. Questa sottoclasse contiene i tipi di proprietà che definiscono la dimensione e la posizione per ogni vista figlio, come appropriato per il gruppo di viste. Come puoi vedere nella figura 2, il gruppo della vista padre definisce i parametri di layout per ogni vista figlia (incluso il gruppo della vista figlio).

Figura 2. Visualizzazione di una gerarchia di viste con parametri di layout associati a ciascuna vista
Notare che ogni sottoclasse LayoutParams ha la propria sintassi per l’impostazione dei valori. Ogni elemento figlio deve definire LayoutParams appropriati per il suo genitore, sebbene possa anche definire diversi LayoutParams per i propri figli.
Tutti i gruppi di viste includono una larghezza e un’altezza ( layout_widthe layout_height) e ogni vista è necessaria per definirli. Molti LayoutParams includono anche margini e bordi opzionali.
Puoi specificare larghezza e altezza con misure esatte, anche se probabilmente non vorrai farlo spesso. Più spesso, utilizzerai una di queste costanti per impostare la larghezza o l’altezza:
- wrap_content dice alla tua vista di ridimensionarsi alle dimensioni richieste dal suo contenuto.
- match_parent indica alla tua vista di diventare grande quanto consentirà il suo gruppo di viste padre.
In generale, si sconsiglia di specificare la larghezza e l’altezza del layout utilizzando unità assolute come i pixel. Invece, utilizzando misurazioni relative come unità di pixel indipendenti dalla densità (dp), wrap_content, o match_parent, è un approccio migliore, perché aiuta a garantire che la tua app venga visualizzata correttamente su una varietà di dimensioni dello schermo del dispositivo. I tipi di misurazione accettati sono definiti nel documento Risorse disponibili .
Posizione layout
La geometria di una vista è quella di un rettangolo. Una vista ha una posizione, espressa come coppia di coordinate sinistra e superiore , e due dimensioni, espresse come larghezza e altezza. L’unità di posizione e dimensioni è il pixel.
È possibile recuperare la posizione di una vista invocando i metodi getLeft() e getTop(). Il primo restituisce la coordinata sinistra, o X, del rettangolo che rappresenta la vista. Quest’ultimo restituisce la coordinata superiore, o Y, del rettangolo che rappresenta la vista. Questi metodi restituiscono entrambi la posizione della vista rispetto al suo genitore. Ad esempio, quando getLeft()restituisce 20, significa che la vista si trova a 20 pixel a destra del bordo sinistro del suo genitore diretto.
Inoltre, vengono offerti diversi metodi convenienti per evitare calcoli non necessari, vale a dire getRight() e getBottom(). Questi metodi restituiscono le coordinate dei bordi destro e inferiore del rettangolo che rappresenta la vista. Ad esempio, chiamata getRight() è simile al seguente calcolo: getLeft() + getWidth().
Dimensioni, spaziatura interna e margini
La dimensione di una vista è espressa con una larghezza e un’altezza. Una vista possiede effettivamente due coppie di valori di larghezza e altezza.
La prima coppia è nota come larghezza misurata e altezza misurata . Queste dimensioni definiscono la dimensione di una vista all’interno del suo genitore. Le dimensioni misurate possono essere ottenute chiamando getMeasuredWidth() e getMeasuredHeight().
La seconda coppia è semplicemente nota come larghezza e altezza , o talvolta larghezza del disegno e altezza del disegno . Queste dimensioni definiscono le dimensioni effettive della vista sullo schermo, al momento del disegno e dopo il layout. Questi valori possono, ma non devono, essere diversi dalla larghezza e dall’altezza misurate. La larghezza e l’altezza possono essere ottenute chiamando getWidth()e getHeight().
Per misurare le sue dimensioni, una vista tiene conto del suo riempimento. Il riempimento è espresso in pixel per le parti sinistra, superiore, destra e inferiore della vista. Il riempimento può essere utilizzato per compensare il contenuto della vista di un numero specifico di pixel. Ad esempio, un riempimento sinistro di 2 spingerà il contenuto della vista di 2 pixel a destra del bordo sinistro. Imbottitura può essere impostato utilizzando il setPadding(int, int, int, int) metodo e interrogato chiamando getPaddingLeft(), getPaddingTop(), getPaddingRight()e getPaddingBottom().
Anche se una vista può definire un riempimento, non fornisce alcun supporto per i margini. Tuttavia, i gruppi di visualizzazione forniscono tale supporto. Fare riferimento a ViewGroup e ViewGroup.MarginLayoutParams per ulteriori informazioni.
Per ulteriori informazioni sulle dimensioni, vedere Valori delle dimensioni .
Layout comuni
Ciascuna sottoclasse della ViewGroup classe fornisce un modo univoco per visualizzare le viste nidificate al suo interno. Di seguito sono riportati alcuni dei tipi di layout più comuni incorporati nella piattaforma Android.
Nota: sebbene sia possibile nidificare uno o più layout all’interno di un altro layout per ottenere il design dell’interfaccia utente, è necessario sforzarsi di mantenere la gerarchia del layout il più superficiale possibile. Il layout disegna più velocemente se ha meno layout nidificati (una gerarchia di visualizzazione ampia è migliore di una gerarchia di visualizzazione profonda).
Layout lineare

Un layout che organizza i suoi figli in una singola riga orizzontale o verticale. Crea una barra di scorrimento se la lunghezza della finestra supera la lunghezza dello schermo.
Layout relativo

Consente di specificare la posizione degli oggetti figlio l’uno rispetto all’altro (figlio A a sinistra del figlio B) o al genitore (allineato alla parte superiore del genitore).
Visualizzazione Web

Visualizza le pagine web.
Creazione di layout con un adattatore
Quando il contenuto del layout è dinamico o non predeterminato, è possibile utilizzare un layout in sottoclassi AdapterView per popolare il layout con le viste in fase di esecuzione. Una sottoclasse della AdapterView classe utilizza un Adapter per associare i dati al suo layout. Si Adapter comporta come un intermediario tra l’origine dati e il AdapterView layout: Adapter recupera i dati (da un’origine come un array o una query di database) e converte ogni voce in una vista che può essere aggiunta al AdapterView layout.
I layout comuni supportati da un adattatore includono:
Visualizzazione elenco

Visualizza un elenco a scorrimento di una singola colonna.
Vista a griglia

Visualizza una griglia a scorrimento di colonne e righe.
Riempimento di una vista dell’adattatore con i dati
È possibile popolare un AdapterView come ListView o GridView associando l’ AdapterView istanza a un Adapter, che recupera i dati da un’origine esterna e crea un View che rappresenta ogni voce di dati.
Android fornisce diverse sottoclassi Adapter utili per recuperare diversi tipi di dati e creare visualizzazioni per un file AdapterView. I due adattatori più comuni sono:
ArrayAdapter
Utilizza questo adattatore quando l’origine dati è un array. Per impostazione predefinita, ArrayAdapter crea una visualizzazione per ogni elemento dell’array richiamando toString() ogni elemento e inserendo il contenuto in un file TextView.
Ad esempio, se si dispone di un array di stringhe che si desidera visualizzare in a ListView, inizializzarne uno nuovo ArrayAdapter utilizzando un costruttore per specificare il layout per ogni stringa e l’array di stringhe:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, myStringArray);
Gli argomenti per questo costruttore sono:
- La tua app Context
- Il layout che contiene un TextView per ogni stringa nell’array
- La matrice di stringhe
Poi basta chiamare setAdapter()il vostro ListView:
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
Per personalizzare l’aspetto di ogni elemento è possibile sovrascrivere il toString() metodo per gli oggetti nell’array. Oppure, per creare una visualizzazione per ogni elemento che sia qualcosa di diverso da un TextView (ad esempio, se desideri una visualizzazione ImageView per ogni elemento dell’array), estendi la ArrayAdapter classe e sostituisci getView() per restituire il tipo di visualizzazione che desideri per ogni elemento.
SimpleCursorAdapter
Usa questo adattatore quando i tuoi dati provengono da un file Cursor. Quando si utilizza SimpleCursorAdapter, è necessario specificare un layout da utilizzare per ogni riga di Cursor e quali colonne di Cursor devono essere inserite in quali visualizzazioni del layout. Ad esempio, se si desidera creare un elenco di nomi di persone e numeri di telefono, è possibile eseguire una query che restituisce un Cursor contenente una riga per ogni persona e colonne per i nomi e i numeri. Si crea quindi un array di stringhe che specifica quali colonne da quelle Cursor desiderate nel layout per ogni risultato e un array intero che specifica le viste corrispondenti che ogni colonna deve essere posizionata:
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};
Quando crei un’istanza di SimpleCursorAdapter, passa il layout da utilizzare per ogni risultato, il Cursor contenente i risultati e questi due array:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);
L’ SimpleCursorAdapter poi crea una vista per ciascuna riga della Cursor utilizzando il layout fornito inserendo ciascun fromColumnselemento nel corrispondente toViews vista.
.
Se, nel corso della vita della tua app, modifichi i dati sottostanti che vengono letti dall’adattatore, dovresti chiamare notifyDataSetChanged(). Questo notificherà alla vista allegata che i dati sono stati modificati e dovrebbe aggiornarsi.
Gestione degli eventi di clic
È possibile rispondere agli eventi di clic su ogni elemento in un AdapterView implementando l’ AdapterView.OnItemClickListener interfaccia. Per esempio:
// Create a message handling object as an anonymous class.
private OnItemClickListener messageClickedHandler = new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
// Do something in response to the click
}
};
listView.setOnItemClickListener(messageClickedHandler);