Layout nelle visualizzazioni
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
. Solitamente, 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.
Gli oggetti View
sono spesso chiamati widget e possono essere una di
molte sottoclassi, come
Button
o
TextView
. Gli oggetti ViewGroup
sono solitamente 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 vocabolario XML semplice che corrisponde alle classi e alle sottoclassi
View
, come quelle per widget e layout. Puoi anche utilizzare l'editor di layout di Android Studio per creare il tuo layout XML mediante un'interfaccia di trascinamento. - Crea un'istanza degli elementi di layout in fase di runtime. L'app può creare oggetti
View
eViewGroup
e manipolarne le 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ù facile fornire layout diversi per dimensioni e orientamenti diversi. Questo aspetto è discusso ulteriormente nella sezione Supporto di schermi di dimensioni diverse.
Il framework Android ti offre la flessibilità di utilizzare uno o entrambi questi metodi per creare la UI della tua app. Ad esempio, puoi dichiarare i layout predefiniti dell'app in XML e poi modificarli in fase di runtime.
Scrivi il codice XML
Con il vocabolario XML di Android, puoi progettare rapidamente layout UI e gli elementi della schermata 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 un TextView
e un 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 l'app, ogni file di layout XML viene compilato in una risorsa View
. Carica la risorsa di layout nell'implementazione
Activity.onCreate()
di callback della tua app. Per farlo, chiama
setContentView()
e passa il riferimento alla risorsa di layout nel formato:
R.layout.layout_file_name
. Ad esempio, se il layout XML
viene salvato come main_layout.xml
, caricalo per il tuo
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 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 oggetti View
che estendono questa classe. Alcuni sono comuni a tutti gli oggetti View
, perché vengono ereditati dalla classe principale View
, 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 della struttura ad albero. Una volta compilata l'app, questo ID viene fatto riferimento come un 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 il parser 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 di 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 di 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:
- 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"/>
- Crea un'istanza dell'oggetto View e acquisiscila dal layout, in genere utilizzando il 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 RelativeLayout
.
In un layout relativo, le viste gemelle possono definire il proprio layout rispetto a un'altra vista di pari livello, a cui viene fatto riferimento dall'ID univoco.
Non è necessario che un ID sia univoco nell'intera struttura ad albero, ma deve essere univoco all'interno della parte della struttura ad albero cercata. Poiché spesso può essere costituito dall'intero albero, l'ideale è renderlo unico.
Parametri di layout
Gli attributi di layout XML denominati layout_something
definiscono
i parametri di layout per View
; 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 ai requisiti del gruppo di visualizzazioni. Come mostrato nella Figura 2, il gruppo delle viste principali definisce i parametri di layout per ogni vista secondaria, incluso il gruppo della vista secondaria.
Ogni sottoclasse LayoutParams
ha la propria sintassi per l'impostazione dei valori. Ogni elemento secondario deve definire un elemento LayoutParams
appropriato per l'elemento padre, ma potrebbe anche definire un
LayoutParams
diverso per i propri elementi secondari.
Tutti i gruppi di visualizzazioni includono una larghezza e un'altezza, utilizzando layout_width
e layout_height
e ogni vista deve essere definita. Molti
LayoutParams
includono margini e bordi facoltativi.
Puoi specificare la larghezza e l'altezza con misure esatte, ma potresti non voler farlo 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 principali.
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 le unità di pixel indipendenti dalla densità (dp), wrap_content
o
match_parent
, perché consentono alla tua app di essere visualizzata correttamente su
una serie di dimensioni dello schermo dei dispositivi. I tipi di misurazione accettati sono definiti nella risorsa di layout.
Posizione layout
Una vista ha una geometria rettangolare. Ha una località, espressa con una coppia di coordinate left e top, e due dimensioni, espresse come larghezza e altezza. L'unità di misura per la posizione e le 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
in relazione a quella principale. Ad esempio, quando getLeft()
restituisce 20, significa che la vista si trova 20 pixel a destra del bordo sinistro dell'elemento principale diretto.
Inoltre, esistono metodi pratici per evitare calcoli non necessari:
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 la larghezza e l'altezza. Una vista ha due coppie di valori di larghezza e altezza.
La prima coppia è nota come larghezza misurata e
altezza misurata. che definiscono l'ampiezza di una vista
all'interno dell'elemento 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 dall'altezza e dalla larghezza misurate, ma non è obbligatorio. Puoi
ottenere la larghezza e l'altezza chiamando
getWidth()
e
getHeight()
.
Per misurare le sue dimensioni, una vista prende in considerazione la sua spaziatura interna. La spaziatura interna è espressa in pixel per le parti sinistra, superiore, destra e inferiore della visualizzazione.
Puoi utilizzare la spaziatura interna per sfalsare i contenuti della visualizzazione di 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 con il metodo
setPadding(int, int, int, int)
ed eseguire query chiamando
getPaddingLeft()
,
getPaddingTop()
,
getPaddingRight()
e
getPaddingBottom()
.
Anche se una visualizzazione può definire una spaziatura interna, non supporta i margini. Tuttavia, i gruppi di visualizzazioni supportano i margini. Consulta le pagine ViewGroup
e ViewGroup.MarginLayoutParams
per saperne di più.
Per ulteriori informazioni sulle dimensioni, consulta 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. La TextView
ha margini e spaziatura interna uniformi applicati attorno a sé, mentre lo strumento Button
mostra come applicarli in modo indipendente a bordi diversi.
Layout comuni
Ogni sottoclasse della classe ViewGroup
offre un modo univoco per
mostrare le viste nidificate al suo interno. Il tipo di layout più flessibile e quello
che offre i migliori strumenti per mantenere superficiali la gerarchia del layout è
ConstraintLayout
.
Di seguito sono riportati alcuni dei tipi di layout comuni integrati nella piattaforma Android.
Organizza i relativi elementi secondari in un'unica riga orizzontale o verticale e crea una barra di scorrimento se la lunghezza della finestra supera quella dello schermo.
Crea elenchi dinamici
Se i contenuti del layout sono dinamici o non predeterminati, puoi utilizzare RecyclerView
o una sottoclasse 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:
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
ad esempio ListView
o
GridView
associando l'istanza AdapterView
a un
Adapter
,
che recupera i dati da un'origine esterna e crea un elemento View
che rappresenta ogni voce di dati.
Android offre diverse sottoclassi di Adapter
utili per recuperare diversi tipi di dati e creare viste per un 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 chiamandotoString()
su ogni elemento e posizionando i contenuti inTextView
.Ad esempio, se hai un array di stringhe che vuoi visualizzare in un
ListView
, inizializza un nuovoArrayAdapter
utilizzando un costruttore per specificare il layout per ogni stringa e 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 di 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 tuoListView
: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 sostituire il metodo
toString()
per gli oggetti nell'array. In alternativa, per creare una vista per ogni elemento diverso daTextView
, ad esempio se vuoi unImageView
per ogni elemento dell'array, estendi la classeArrayAdapter
e sostituiscigetView()
per restituire il tipo di visualizzazione che vuoi per ogni elemento. - La tua app
SimpleCursorAdapter
- Utilizza questo adattatore quando i dati provengono da un dispositivo
Cursor
. Quando utilizziSimpleCursorAdapter
, specifica un layout da utilizzare per ogni riga inCursor
e quali colonne inCursor
vuoi inserire nelle visualizzazioni del layout che ti interessa. Ad esempio, se vuoi creare un elenco di nomi e numeri di telefono delle persone, puoi eseguire una query che restituiscaCursor
contenente una riga per ogni persona e colonne per i nomi e i numeri. Successivamente, creerai un array di stringhe che specifica quali colonne diCursor
vuoi nel layout per ogni risultato e un array di numeri interi che specifica le viste corrispondenti che deve essere posizionato ogni 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, ilCursor
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);
L'elemento
SimpleCursorAdapter
crea quindi una vista per ogni riga inCursor
utilizzando il layout fornito, inserendo ogni elementofromColumns
nella visualizzazionetoViews
corrispondente.
Se nel corso del ciclo di vita dell'app modifichi i dati sottostanti che vengono letti dall'adattatore, chiama
notifyDataSetChanged()
.
In questo modo viene notificato alla vista allegata che i dati sono stati modificati e vengono aggiornati 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 nella demo dell'app Girasole su GitHub.