Layout in Visualizzazioni

Prova la modalità di scrittura
Jetpack Compose è il toolkit per l'interfaccia utente consigliato per Android. Scopri come utilizzare i layout in Scrivi.

Un layout definisce la struttura di un'interfaccia utente nella tua app, ad esempio in un'attività. Tutti gli elementi del layout vengono creati utilizzando una gerarchia di oggetti View e ViewGroup. In genere, un elemento View disegna qualcosa che l'utente può vedere e con cui può interagire. Un ViewGroup è un container invisibile che definisce la struttura del layout per View e altri oggetti ViewGroup, come mostrato nella figura 1.

Figura 1. Illustrazione di una gerarchia di viste, che definisce un layout dell'interfaccia utente.

Gli oggetti View sono spesso chiamati widget e possono essere una delle tante sottoclassi, come Button o TextView. Gli oggetti ViewGroup sono di solito chiamati layout e possono essere uno dei tanti tipi che forniscono una struttura di layout diversa, ad esempio LinearLayout o ConstraintLayout.

Puoi dichiarare un layout in due modi:

  • Dichiara 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 usare l'editor di layout di Android Studio per creare il tuo layout XML mediante un'interfaccia di trascinamento.

  • Crea un'istanza degli elementi del layout in fase di esecuzione. La tua app può creare oggetti View e ViewGroup e manipolare le relative proprietà in modo programmatico.

La dichiarazione della UI in XML ti consente di separare la presentazione della tua app dal codice che ne controlla il comportamento. Con i file XML è anche più semplice fornire layout diversi per dimensioni e orientamenti diversi. Questo argomento viene discusso più in dettaglio nella sezione Supporto di schermi di dimensioni diverse.

Il framework Android ti offre la flessibilità di utilizzare uno o entrambi i metodi per creare l'UI della tua app. Ad esempio, puoi dichiarare i layout predefiniti dell'app in XML e poi modificarli in fase di runtime.

Scrivi il file XML

Con il vocabolario XML di Android, puoi progettare rapidamente layout UI 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 principale, che deve essere un oggetto View o ViewGroup. Dopo aver definito l'elemento principale, puoi aggiungere altri oggetti o widget di layout come elementi secondari per creare gradualmente una gerarchia View che definisce il layout. Ad esempio, ecco un layout XML che utilizza un LinearLayout verticale per contenere TextView e 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'estensione .xml nella directory res/layout/ del tuo progetto Android in modo che venga compilato correttamente.

Per ulteriori informazioni sulla sintassi di un file XML di layout, consulta Risorsa di layout.

Carica la risorsa XML

Quando compili la tua app, ogni file di layout XML viene compilato in una risorsa View. Carica la risorsa di layout nell'implementazione di callback Activity.onCreate() dell'app. Per farlo, chiama setContentView() e passa il riferimento alla tua risorsa di layout nel formato: R.layout.layout_file_name. Ad esempio, se il layout XML è salvato come main_layout.xml, caricalo per Activity come segue:

Kotlin

fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}

Java

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

Il framework Android chiama il metodo di callback onCreate() in Activity all'avvio di Activity. Per ulteriori informazioni sui cicli di vita delle attività, consulta Introduzione alle attività.

Attributi

Ogni oggetto View e ViewGroup supporta una propria varietà di attributi XML. Alcuni attributi sono specifici di un oggetto View. Ad esempio, TextView supporta l'attributo textSize. Tuttavia, questi attributi vengono ereditati anche dagli eventuali oggetti View che estendono questa classe. Alcuni sono comuni a tutti gli oggetti View, perché vengono ereditati dalla classe View principale, come l'attributo id. Altri attributi sono considerati parametri di layout, ovvero attributi che descrivono determinati orientamenti di layout dell'oggetto View, come definito dall'oggetto ViewGroup principale dell'oggetto.

ID

A qualsiasi oggetto View può essere associato un ID intero per identificare in modo univoco View all'interno dell'albero. Una volta compilata l'app, questo ID viene indicato come numero intero, ma in genere l'ID viene assegnato nel file XML di layout come stringa nell'attributo id. Si tratta di un attributo XML comune a tutti gli oggetti View ed è definito dalla classe View. Lo usi molto spesso. La sintassi di un ID all'interno di un tag XML è la seguente:

android:id="@+id/my_button"

Il simbolo at (@) all'inizio della stringa indica che l'analizzatore sintattico XML analizza ed espande il resto della stringa ID e la identifica come risorsa ID. Il simbolo più (+) indica che si tratta di un nuovo nome risorsa che deve essere creato e aggiunto alle risorse nel file R.java.

Il framework Android offre molte altre risorse di ID. Quando fai riferimento a un ID risorsa Android, non è necessario il simbolo più, ma devi aggiungere lo spazio dei nomi del pacchetto android come segue:

android:id="@android:id/empty"

Lo spazio dei nomi del pacchetto android indica che fai riferimento a un ID della classe delle risorse android.R, anziché della classe delle risorse locali.

Per creare viste e farvi riferimento dalla tua app, puoi utilizzare uno schema comune come segue:

  1. Definisci una vista nel file di layout e assegnale un ID univoco, come nell'esempio seguente:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
    
  2. Crea un'istanza dell'oggetto view e acquisiscila dal layout, in genere nel metodo onCreate(), come mostrato nell'esempio seguente:

    Kotlin

    val myButton: Button = findViewById(R.id.my_button)
    

    Java

    Button myButton = (Button) findViewById(R.id.my_button);
    

La definizione degli ID per gli oggetti vista è importante durante la creazione di un elemento RelativeLayout. In un layout relativo, le viste gemelle possono definire il proprio layout rispetto a un'altra vista di pari livello, a cui fa riferimento l'ID univoco.

Non è necessario che un ID sia univoco nell'intero albero, ma deve essere univoco all'interno della parte della struttura ad albero che cerchi. Spesso potrebbe essere l'intero albero, quindi è meglio renderlo unico, quando possibile.

Parametri di layout

Gli attributi di layout XML denominati layout_something definiscono i parametri di layout per View e sono appropriati per il ViewGroup in cui risiede.

Ogni classe ViewGroup implementa una classe nidificata che estende ViewGroup.LayoutParams. Questa sottoclasse contiene tipi di proprietà che definiscono le dimensioni e la posizione di ogni vista secondaria, in base al gruppo di visualizzazioni. Come mostrato nella Figura 2, il gruppo delle viste padre definisce i parametri di layout per ogni vista secondaria, incluso il gruppo delle viste secondarie.

Figura 2. Visualizzazione di una gerarchia delle viste con parametri di layout associati a ciascuna vista.

Ogni sottoclasse LayoutParams ha la propria sintassi per l'impostazione dei valori. Ogni elemento secondario deve definire un elemento LayoutParams appropriato per il relativo elemento principale, ma potrebbe anche definire un LayoutParams diverso per i propri elementi secondari.

Tutti i gruppi di visualizzazioni includono larghezza e altezza, utilizzando layout_width e layout_height e ogni vista deve definirli. Molti LayoutParams includono margini e bordi facoltativi.

Puoi specificare la larghezza e l'altezza con misurazioni esatte, ma potresti non volerlo fare spesso. Più spesso, utilizzi una di queste costanti per impostare la larghezza o l'altezza:

  • wrap_content: indica alla visualizzazione di adattarsi alle dimensioni richieste dai suoi contenuti.
  • match_parent: indica alla visualizzazione di raggiungere le dimensioni consentite del gruppo di visualizzazioni principale.

In generale, sconsigliamo di specificare la larghezza e l'altezza del layout utilizzando unità assolute come i pixel. Un approccio migliore consiste nell'utilizzare misurazioni relative, ad esempio unità di pixel indipendenti dalla densità (dp), wrap_content o match_parent, perché consentono all'app di essere visualizzata correttamente su una serie di dimensioni dello schermo dei dispositivi. I tipi di misurazione accettati sono definiti nella sezione Risorsa layout.

Posizione layout

Una vista ha una geometria rettangolare. Include una posizione, espressa come coppia di coordinate left e top, e due dimensioni, espresse come larghezza e altezza. L'unità per posizione e dimensioni è il pixel.

Puoi recuperare la posizione di una vista richiamando i metodi getLeft() e getTop(). Il primo restituisce la coordinata sinistra (x) del rettangolo che rappresenta la vista. Quest'ultimo restituisce la coordinata superiore (y) del rettangolo che rappresenta la vista. Questi metodi restituiscono la posizione della vista relativa a quella principale. Ad esempio, se getLeft() restituisce 20, significa che la vista si trova 20 pixel a destra del bordo sinistro del relativo bordo principale diretto.

Inoltre, esistono metodi pratici per evitare calcoli inutili, ovvero getRight() e getBottom(). Questi metodi restituiscono le coordinate dei bordi destro e inferiore del rettangolo che rappresenta la vista. Ad esempio, la chiamata a getRight() è simile al seguente calcolo: getLeft() + getWidth().

Dimensioni, spaziatura interna e margini

Le dimensioni di una visualizzazione sono espresse con larghezza e altezza. Una vista ha due coppie di valori di larghezza e altezza.

La prima coppia è nota come larghezza misurata e altezza misurata. Queste dimensioni definiscono l'ampiezza di una vista all'interno di quella principale. Puoi ottenere le dimensioni misurate chiamando getMeasuredWidth() e getMeasuredHeight().

La seconda coppia è nota come larghezza e altezza o, a volte, larghezza di disegno e altezza di disegno. Queste dimensioni definiscono le dimensioni effettive della visualizzazione sullo schermo, al momento del disegno e dopo il layout. Questi valori possono essere diversi dalla larghezza e dall'altezza misurate, ma non è obbligatorio. Puoi ottenere la larghezza e l'altezza chiamando getWidth() e getHeight().

Per misurare le dimensioni, una vista prende in considerazione la sua spaziatura interna. La spaziatura interna è espressa in pixel per la parte sinistra, superiore, destra e inferiore della visualizzazione. Puoi utilizzare la spaziatura interna per spostare il contenuto della visualizzazione in base a un numero specifico di pixel. Ad esempio, una spaziatura interna sinistra di due spinge i contenuti della visualizzazione di due pixel a destra del bordo sinistro. Puoi impostare la spaziatura interna utilizzando il metodo setPadding(int, int, int, int) ed eseguire una query chiamando getPaddingLeft(), getPaddingTop(), getPaddingRight() e getPaddingBottom().

Sebbene una vista possa definire una spaziatura interna, non supporta i margini. Tuttavia, i gruppi di visualizzazioni supportano i margini. Consulta le pagine ViewGroup e ViewGroup.MarginLayoutParams per ulteriori informazioni.

Per ulteriori informazioni sulle dimensioni, consulta la sezione Dimensione.

Oltre a impostare i margini e la spaziatura interna in modo programmatico, puoi impostarli anche nei layout XML, come mostrato nell'esempio seguente:

  <?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:layout_margin="16dp"
                android:padding="8dp"
                android:text="Hello, I am a TextView" />
      <Button android:id="@+id/button"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="16dp"
              android:paddingBottom="4dp"
              android:paddingEnd="8dp"
              android:paddingStart="8dp"
              android:paddingTop="4dp"
              android:text="Hello, I am a Button" />
  </LinearLayout>
  

L'esempio precedente mostra l'applicazione di margine e spaziatura interna. L'elemento TextView presenta margini e spaziatura uniforme uniformi e l'elemento Button mostra come applicarli in modo indipendente a bordi diversi.

Layout comuni

Ogni sottoclasse della classe ViewGroup fornisce un modo univoco per visualizzare le viste nidificate al suo interno. Il tipo di layout più flessibile e quello che offre i migliori strumenti per mantenere una gerarchia del layout ridotta è ConstraintLayout.

Di seguito sono riportati alcuni dei tipi di layout comuni integrati nella piattaforma Android.

Creare un layout lineare

Organizza gli elementi secondari in un'unica riga orizzontale o verticale e crea una barra di scorrimento se la lunghezza della finestra supera la lunghezza dello schermo.

Crea app web in WebView

Mostra le pagine web.

Creare elenchi dinamici

Quando i contenuti del layout sono dinamici o non sono predeterminati, puoi utilizzare RecyclerView o una sottoclasse di AdapterView. RecyclerView è in genere l'opzione migliore, perché utilizza la memoria in modo più efficiente rispetto a AdapterView.

I layout comuni possibili con RecyclerView e AdapterView includono:

Elenco

Visualizza un elenco scorrevole a colonne singole.

Griglia

Visualizza una griglia scorrevole di colonne e righe.

RecyclerView offre più possibilità e la possibilità di creare un gestore di layout personalizzato.

Inserire i dati in una visualizzazione adattatore

Puoi completare un elemento AdapterView come ListView o GridView associando l'istanza AdapterView a un Adapter, che recupera i dati da un'origine esterna e crea un valore View che rappresenta ogni voce di dati.

Android offre diverse sottoclassi di Adapter utili per recuperare diversi tipi di dati e creare viste per AdapterView. I due adattatori più comuni sono:

ArrayAdapter
Utilizza questo adattatore quando l'origine dati è un array. Per impostazione predefinita, ArrayAdapter crea una vista per ogni elemento dell'array chiamando toString() su ciascun elemento e posizionando i contenuti in un TextView.

Ad esempio, se hai un array di stringhe che vuoi visualizzare in un elemento ListView, inizializza un nuovo ArrayAdapter utilizzando un costruttore per specificare il layout per ogni stringa e per l'array di stringhe:

Kotlin

    val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
    

Java

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, myStringArray);
    

Gli argomenti per questo costruttore sono i seguenti:

  • La tua app Context
  • Il layout che contiene un TextView per ogni stringa nell'array
  • L'array di stringhe

Quindi chiama setAdapter() sul tuo ListView:

Kotlin

    val listView: ListView = findViewById(R.id.listview)
    listView.adapter = adapter
    

Java

    ListView listView = (ListView) findViewById(R.id.listview);
    listView.setAdapter(adapter);
    

Per personalizzare l'aspetto di ogni elemento, puoi eseguire l'override del metodo toString() per gli oggetti nel tuo array. In alternativa, per creare una vista per ogni elemento diverso da TextView, ad esempio se vuoi un elemento ImageView per ogni elemento dell'array, estendi la classe ArrayAdapter e sostituisci getView() per restituire il tipo di vista che vuoi per ogni elemento.

SimpleCursorAdapter
Utilizza questo adattatore quando i dati provengono da un Cursor. Quando utilizzi SimpleCursorAdapter, specifica un layout da utilizzare per ogni riga in Cursor e quali colonne in Cursor vuoi che vengano inserite nelle visualizzazioni del layout che vuoi. Ad esempio, se vuoi creare un elenco di nomi e numeri di telefono delle persone, puoi eseguire una query che restituisca un Cursor contenente una riga per ogni persona e le colonne per i nomi e i numeri. Successivamente, creerai un array di stringhe che specifica quali colonne di Cursor vuoi nel layout per ogni risultato e un array di numeri interi che specifichi le viste corrispondenti di ciascuna colonna:

Kotlin

    val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME,
                              ContactsContract.CommonDataKinds.Phone.NUMBER)
    val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
    

Java

    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:

Kotlin

    val adapter = SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0)
    val listView = getListView()
    listView.adapter = adapter
    

Java

    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
    ListView listView = getListView();
    listView.setAdapter(adapter);
    

SimpleCursorAdapter crea quindi una vista per ogni riga in Cursor utilizzando il layout fornito, inserendo ogni elemento fromColumns nella vista toViews corrispondente.

Se nel corso della tua app modifichi i dati sottostanti letti dall'adattatore, chiama notifyDataSetChanged(). In questo modo viene comunicato alla visualizzazione allegata che i dati sono stati modificati e si aggiornano automaticamente.

Gestire gli eventi di clic

Puoi rispondere agli eventi di clic su ogni elemento in un AdapterView implementando l'interfaccia AdapterView.OnItemClickListener. Ecco alcuni esempi:

Kotlin

listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
    // Do something in response to the click.
}

Java

// 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);

Risorse aggiuntive

Scopri come vengono utilizzati i layout nell'app demo Sunflower su GitHub.