Libro di ricette con schermo grande

Android fornisce tutti gli ingredienti per le app a cinque stelle su schermo grande. Le ricette in questo libro di ricette selezionano e combinano ingredienti scelti per risolvere problemi di sviluppo specifici. Ogni ricetta include best practice, esempi di codice di qualità e istruzioni dettagliate per aiutarti a diventare un grande chef.

Valutazioni a stelle

Le ricette sono valutate a stelle in base a quanto sono conformi alle norme sulla qualità delle app per schermi grandi.

Voto: cinque stelle Soddisfa i criteri per il livello 1, schermo grande con differenziazione
Voto: quattro stelle Soddisfa i criteri per il livello 2, ottimizzato per schermo di grandi dimensioni
Voto: tre stelle Soddisfa i criteri per il livello 3, schermo grande pronto
Voto: due stelle Fornisce alcune funzionalità per schermi grandi, ma non rispetta le norme sulla qualità delle app per schermi grandi
Valutazione a una stella Soddisfa le esigenze di un caso d'uso specifico, ma non supporta correttamente gli schermi di grandi dimensioni

Supporto per le fotocamere dei Chromebook

Voto: tre stelle

Fatti notare su Google Play dagli utenti di Chromebook.

Se l'app Fotocamera può funzionare solo con funzionalità di base della fotocamera, non lasciare che gli store impediscano agli utenti di Chromebook di installare l'app solo perché hai inavvertitamente specificato le funzionalità avanzate della fotocamera disponibili su telefoni di fascia alta.

I Chromebook sono dotati di una fotocamera anteriore integrata (rivolta agli utenti) che funziona bene per videoconferenze, istantanee e altre applicazioni. Tuttavia, non tutti i Chromebook hanno una fotocamera posteriore (rivolta verso il mondo) e la maggior parte delle fotocamere rivolte agli utenti non supporta la messa a fuoco automatica o il flash.

Best practice

Le app versatili della fotocamera supportano tutti i dispositivi indipendentemente dalla configurazione della fotocamera: dispositivi con fotocamere anteriori, posteriori e esterne collegate tramite USB.

Per assicurarti che gli store rendano disponibile la tua app per il maggior numero di dispositivi, dichiara sempre tutte le funzionalità della fotocamera utilizzate dall'app e indica esplicitamente se sono necessarie o meno.

Ingredienti

  • Autorizzazione CAMERA: consente alla tua app di accedere alle fotocamere di un dispositivo
  • Elemento manifest <uses-feature>: indica agli store le funzionalità utilizzate dalla tua app.
  • Attributo required: indica agli store se l'app può funzionare senza una funzionalità specificata

Passi

Riepilogo

Dichiara l'autorizzazione CAMERA. Dichiara le funzionalità della fotocamera che forniscono il supporto di base della videocamera. Specifica se ogni funzionalità è obbligatoria o meno.

1. Dichiara l'autorizzazione CAMERA

Aggiungi la seguente autorizzazione al file manifest dell'app:

<uses-permission android:name="android.permission.CAMERA" />
2. Dichiarare le funzionalità di base della fotocamera

Aggiungi le seguenti funzionalità al file manifest dell'app:

<uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
3. Specifica se ogni funzionalità è obbligatoria

Imposta android:required="false" per la funzionalità android.hardware.camera.any per consentire l'accesso alla tua app da parte di dispositivi con qualsiasi tipo di fotocamera integrata o esterna o senza videocamera.

Per le altre funzionalità, imposta android:required="false" per assicurarti che i dispositivi come Chromebook che non hanno fotocamere posteriori, messa a fuoco automatica o flash possano accedere alla tua app negli store.

Risultati

Gli utenti di Chromebook possono scaricare e installare la tua app da Google Play e da altri store. Inoltre, i dispositivi che supportano la fotocamera con funzionalità complete, come gli smartphone, non saranno limitati nella funzionalità della fotocamera.

Impostando esplicitamente le funzionalità della fotocamera supportate dalla tua app e specificando quelle necessarie, hai reso disponibile la tua app per il maggior numero possibile di dispositivi.

Risorse aggiuntive

Per ulteriori informazioni, vedi Funzionalità hardware della videocamera nella documentazione di <uses-feature>.

Orientamento dell'app limitato sui telefoni, ma non sui dispositivi con schermi grandi

Voto: due stelle

L'app funziona perfettamente sui telefoni con orientamento verticale, pertanto hai limitato l'orientamento solo all'orientamento verticale. Ma c'è l'opportunità di fare di più su schermi di grandi dimensioni con orientamento orizzontale.

Come puoi farlo in entrambi i modi: limitare l'app all'orientamento verticale su schermi piccoli e abilitare l'orientamento orizzontale su quelli grandi?

Best practice

Le app migliori rispettano le preferenze dell'utente, ad esempio l'orientamento del dispositivo.

Le linee guida relative alla qualità delle app per schermi grandi consigliano che le app supportino tutte le configurazioni dei dispositivi, inclusi l'orientamento verticale e orizzontale, la modalità multi-finestra e gli stati piegati e aperti dei dispositivi pieghevoli. Le app devono ottimizzare layout e interfacce utente per le diverse configurazioni e devono salvare e ripristinare lo stato durante le modifiche alla configurazione.

Questa ricetta è una soluzione temporanea, un pizzico di supporto per uno schermo di grandi dimensioni. Usa la formula finché non riesci a migliorare l'app per fornire il supporto completo per tutte le configurazioni dispositivo.

Ingredienti

  • screenOrientation: impostazione del file manifest dell'app che ti consente di specificare in che modo l'app deve rispondere alle variazioni di orientamento del dispositivo
  • Jetpack WindowManager: insieme di librerie che consentono di determinare le dimensioni e il formato della finestra dell'app; compatibile con le versioni precedenti al livello API 14
  • Activity#setRequestedOrientation(): metodo che consente di modificare l'orientamento dell'app in fase di runtime

Passi

Riepilogo

Consenti all'app di gestire le modifiche di orientamento per impostazione predefinita nel file manifest dell'app. In fase di runtime, determina le dimensioni della finestra dell'app. Se la finestra dell'app è di piccole dimensioni, limita l'orientamento dell'app sostituendo l'impostazione di orientamento del file manifest.

1. Specifica l'impostazione di orientamento nel file manifest dell'app

Puoi evitare di dichiarare l'elemento screenOrientation del file manifest dell'app (in questo caso l'orientamento predefinito sarà unspecified) oppure impostare l'orientamento dello schermo su fullUser. Se l'utente non ha bloccato la rotazione basata sul sensore, la tua app supporterà tutti gli orientamenti del dispositivo.

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

La differenza tra l'uso di unspecified e fullUser è sottile ma importante. Se non dichiari un valore screenOrientation, il sistema sceglie l'orientamento, che potrebbe variare da dispositivo a dispositivo. La specifica di fullUser, invece, corrisponde maggiormente al comportamento che l'utente ha definito per il dispositivo: se l'utente ha bloccato la rotazione basata sul sensore, l'app segue la preferenza dell'utente; in caso contrario, il sistema consente uno dei quattro possibili orientamenti dello schermo (verticale, orizzontale, verticale opposto o orizzontale inverso). Vedi android:screenOrientation.

2. Determinare le dimensioni dello schermo

Se il file manifest è impostato in modo da supportare tutti gli orientamenti consentiti dall'utente, puoi specificare l'orientamento dell'app in modo programmatico in base alle dimensioni dello schermo.

Aggiungi le librerie Jetpack WindowManager al file build.gradle o build.gradle.kts del modulo:

Kotlin

implementation("androidx.window:window:version")
implementation("androidx.window:window-core:version")

trendy

implementation 'androidx.window:window:version'
implementation 'androidx.window:window-core:version'

Utilizza il metodo Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics() per ottenere le dimensioni dello schermo del dispositivo come oggetto WindowMetrics. Le metriche relative alle finestre possono essere confrontate con le relative classi per decidere quando limitare l'orientamento.

Le classi di dimensioni Windows forniscono i punti di interruzione tra schermi piccoli e grandi.

Utilizza i punti di interruzione WindowWidthSizeClass#COMPACT e WindowHeightSizeClass#COMPACT per determinare le dimensioni dello schermo:

Kotlin

/** Determines whether the device has a compact screen. **/
fun compactScreen() : Boolean {
    val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this)
    val width = metrics.bounds.width()
    val height = metrics.bounds.height()
    val density = resources.displayMetrics.density
    val windowSizeClass = WindowSizeClass.compute(width/density, height/density)

    return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT ||
        windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT
}

Java

/** Determines whether the device has a compact screen. **/
private boolean compactScreen() {
    WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this);
    int width = metrics.getBounds().width();
    int height = metrics.getBounds().height();
    float density = getResources().getDisplayMetrics().density;
    WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density);
    return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT ||
                windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT;
}
    Nota:
  • Gli esempi precedenti sono implementati come metodi di un'attività; pertanto, l'attività viene rimossa come this nell'argomento computeMaximumWindowMetrics().
  • Viene utilizzato il metodo computeMaximumWindowMetrics() al posto di computeCurrentWindowMetrics() perché l'app può essere avviata in modalità multi-finestra, che ignora l'impostazione dell'orientamento dello schermo. È inutile determinare le dimensioni della finestra dell'app e sostituire l'impostazione di orientamento, a meno che la finestra dell'app non occupi l'intero schermo del dispositivo.

Consulta WindowManager per istruzioni su come dichiarare le dipendenze per rendere disponibile il metodo computeMaximumWindowMetrics() nella tua app.

3. Esegui l'override dell'impostazione del manifest dell'app

Una volta stabilito che le dimensioni dello schermo del dispositivo sono compatte, puoi chiamare Activity#setRequestedOrientation() per sostituire l'impostazione screenOrientation del file manifest:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    requestedOrientation = if (compactScreen())
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
        ActivityInfo.SCREEN_ORIENTATION_FULL_USER
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    val container: ViewGroup = binding.container

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(object : View(this) {
        override fun onConfigurationChanged(newConfig: Configuration?) {
            super.onConfigurationChanged(newConfig)
            requestedOrientation = if (compactScreen())
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
                ActivityInfo.SCREEN_ORIENTATION_FULL_USER
        }
    })
}

Java

@Override
protected void onCreate(Bundle savedInstance) {
    super.onCreate(savedInstanceState);
    if (compactScreen()) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
    }
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    ViewGroup container = binding.container;

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(new View(this) {
        @Override
        protected void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (compactScreen()) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
            }
        }
    });
}

Aggiungendo la logica ai metodi onCreate() e View.onConfigurationChanged(), puoi ottenere il numero massimo di metriche della finestra e sostituire l'impostazione di orientamento ogni volta che l'attività viene ridimensionata o spostata tra i display, ad esempio dopo una rotazione del dispositivo o quando un dispositivo pieghevole è piegato o aperto. Per saperne di più su quando vengono apportate le modifiche alla configurazione e quando causano la ricreazione delle attività, consulta Gestire le modifiche alla configurazione.

Risultati

L'orientamento dell'app dovrebbe essere verticale sugli schermi piccoli, indipendentemente dalla rotazione del dispositivo. Sugli schermi di grandi dimensioni, l'app dovrebbe supportare l'orientamento orizzontale e verticale.

Risorse aggiuntive

Per ricevere assistenza per l'upgrade dell'app in modo che supporti sempre tutte le configurazioni dei dispositivi, consulta le seguenti risorse:

Pausa e ripresa della riproduzione di contenuti multimediali con la barra spaziatrice della tastiera esterna

Voto: quattro stelle

L'ottimizzazione degli schermi di grandi dimensioni include la possibilità di gestire input da tastiera esterni, ad esempio reagire alla pressione della barra spaziatrice per mettere in pausa o riprendere la riproduzione di video e altri contenuti multimediali. Questa funzionalità è particolarmente utile per i tablet, che spesso si connettono a tastiere esterne, e i Chromebook, che in genere sono dotati di tastiere esterne, ma possono essere utilizzati in modalità tablet.

Quando i contenuti multimediali sono l'unico elemento della finestra (ad esempio la riproduzione di video a schermo intero), rispondi agli eventi di pressione dei tasti a livello di attività o, in Jetpack Compose, a livello di schermo.

Best practice

Ogni volta che l'app riproduce un file multimediale, gli utenti devono essere in grado di mettere in pausa e riprendere la riproduzione premendo la barra spaziatrice su una tastiera fisica.

Ingredienti

  • KEYCODE_SPACE: costante del codice della chiave per la barra spaziatrice.

Compose

  • onPreviewKeyEvent: Modifier che consente a un componente di intercettare gli eventi chiave hardware quando viene attivato il componente stesso (o uno dei suoi elementi secondari).
  • onKeyEvent: simile a onPreviewKeyEvent, questa Modifier consente a un componente di intercettare gli eventi chiave hardware quando il componente in questione (o uno dei suoi elementi secondari) è attivo.

Viste

  • onKeyUp(): chiamato quando una chiave viene rilasciata e non viene gestita da una visualizzazione all'interno di un'attività.

Passi

Riepilogo

Le app e le app basate sulle visualizzazioni basate su Jetpack Compose rispondono alla pressione dei tasti della tastiera in modo simile: l'app deve ascoltare gli eventi di pressione dei tasti, filtrare gli eventi e rispondere alle pressioni dei tasti selezionate, ad esempio la pressione dei tasti della barra spaziatrice.

1. Ascolta gli eventi della tastiera

Viste

In un'attività nella tua app, esegui l'override del metodo onKeyUp():

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    ...
}

Java

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    ...
}

Il metodo viene richiamato ogni volta che viene rilasciato un tasto premuto, quindi si attiva esattamente una volta per ogni pressione di un tasto.

Compose

Con Jetpack Compose, puoi utilizzare il tasto di modifica onPreviewKeyEvent o onKeyEvent all'interno dello schermo che gestisce la sequenza di tasti:

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

oppure

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

2. Filtra pressioni della barra spaziatrice

All'interno del metodo onKeyUp() o dei metodi di modifica Scrivi onPreviewKeyEvent e onKeyEvent, filtra per KeyEvent.KEYCODE_SPACE per inviare l'evento corretto al componente multimediale:

Viste

Kotlin

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback()
    return true
}
return false

Java

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback();
    return true;
}
return false;

Compose

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

oppure

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

Risultati

Ora la tua app può rispondere alla pressione dei tasti della barra spaziatrice per mettere in pausa e riprendere un video o altri contenuti multimediali.

Risorse aggiuntive

Per scoprire di più sugli eventi da tastiera e su come gestirli, vedi Gestire l'input da tastiera.

Rifiuti del palmo dello stilo

Voto: cinque stelle

Uno stilo può essere uno strumento estremamente produttivo e creativo su schermi di grandi dimensioni. Quando però gli utenti disegnano, scrivono o interagiscono con un'app usando uno stilo, a volte toccano lo schermo con il palmo delle mani. L'evento touch può essere segnalato alla tua app prima che il sistema riconosca e lo ignori come un tocco accidentale con il palmo della mano.

Best practice

L'app deve identificare gli eventi tocco estranei e ignorarli. Android annulla un tocco con il palmo inviando un oggetto MotionEvent. Controlla se nell'oggetto è presente ACTION_CANCEL o ACTION_POINTER_UP e FLAG_CANCELED per determinare se rifiutare il gesto causato dal tocco del palmo.

Ingredienti

  • MotionEvent: rappresenta gli eventi di tocco e movimento. Contiene le informazioni necessarie per determinare se un evento deve essere ignorato.
  • OnTouchListener#onTouch(): riceve MotionEvent oggetti.
  • MotionEvent#getActionMasked(): restituisce l'azione associata a un evento di movimento.
  • ACTION_CANCEL: costante MotionEvent che indica che un gesto deve essere annullato.
  • ACTION_POINTER_UP: costante MotionEvent che indica che un puntatore diverso dal primo puntatore è salito (ovvero ha rinunciato al contatto con lo schermo del dispositivo).
  • FLAG_CANCELED: costante MotionEvent che indica che il sollevamento del puntatore ha causato un evento tocco involontario. Aggiunto agli eventi ACTION_POINTER_UP e ACTION_CANCEL su Android 13 (livello API 33) e versioni successive.

Passi

Riepilogo

Esamina gli oggetti MotionEvent inviati alla tua app. Usa le API MotionEvent per determinare le caratteristiche degli eventi:

  • Eventi da puntamento: controlla ACTION_CANCEL. Su Android 13 e versioni successive, controlla anche la presenza di FLAG_CANCELED.
  • Eventi multipunto: su Android 13 e versioni successive, controlla ACTION_POINTER_UP e FLAG_CANCELED.

Rispondere agli eventi ACTION_CANCEL e ACTION_POINTER_UP/FLAG_CANCELED.

1. Acquisisci oggetti di eventi di movimento

Aggiungi OnTouchListener alla tua app:

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        // Process motion event.
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    // Process motion event.
});
2. Determina l'azione dell'evento e i flag

Controlla ACTION_CANCEL, che indica un evento a punto singolo su tutti i livelli API. Su Android 13 e versioni successive, controlla ACTION_POINTER_UP per FLAG_CANCELED.

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        when (event.actionMasked) {
            MotionEvent.ACTION_CANCEL -> {
                //Process canceled single-pointer motion event for all SDK versions.
            }
            MotionEvent.ACTION_POINTER_UP -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
                   (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                    //Process canceled multi-pointer motion event for Android 13 and higher.
                }
            }
        }
        true
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_CANCEL:
            // Process canceled single-pointer motion event for all SDK versions.
        case MotionEvent.ACTION_UP:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
               (event.getFlags() & MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                //Process canceled multi-pointer motion event for Android 13 and higher.
            }
    }
    return true;
});
3. Annulla il gesto

Una volta identificato un tocco del palmo, puoi annullare gli effetti del gesto sullo schermo.

L'app deve conservare una cronologia delle azioni degli utenti per poter annullare input involontari, ad esempio tocchi con il palmo, della mano. Per un esempio, vedi Implementare un'app di disegno di base nel codelab Migliorare il supporto dello stilo in un'app per Android.

Risultati

La tua app ora può identificare e rifiutare i tocchi del palmo per gli eventi multi-pointer su livelli API Android 13 e successivi, nonché per gli eventi a punto singolo su tutti i livelli API.

Risorse aggiuntive

Per ulteriori informazioni, consulta le seguenti risorse:

Gestione dello stato di WebView

Voto: tre stelle

WebView è un componente di uso comune che offre un sistema avanzato per la gestione dello stato. Un WebView deve mantenere il proprio stato e la posizione di scorrimento tra le modifiche alla configurazione. Un'WebView può perdere la posizione di scorrimento quando l'utente ruota il dispositivo o apre uno smartphone pieghevole, il che costringe a scorrere di nuovo dalla parte superiore di WebView alla posizione di scorrimento precedente.

Best practice

Riduci al minimo il numero di volte in cui viene ricreata una WebView. WebView è in grado di gestire il suo stato e puoi sfruttare questa qualità gestendo il maggior numero possibile di modifiche alla configurazione. La tua app deve gestire le modifiche alla configurazione perché anche la funzionalità di creazione di Activity (il modo in cui il sistema gestisce le modifiche alla configurazione) ricrea la WebView, causando la perdita dello stato di WebView.

Ingredienti

  • android:configChanges: attributo dell'elemento manifest <activity>. Elenca le modifiche alla configurazione gestite dall'attività.
  • View#invalidate(): metodo che causa la rielaborazione di una vista. Ereditata da WebView.

Passi

Riepilogo

Per salvare lo stato WebView, evita il più possibile la ricreazione di Activity, quindi lascia invalidare WebView in modo che possa essere ridimensionata mantenendo lo stato.

1. Aggiungi modifiche alla configurazione al file AndroidManifest.xml dell'app

Per evitare la ricreazione di attività, specifica le modifiche alla configurazione gestite dall'app (anziché dal sistema):

<activity
  android:name=".MyActivity"
  android:configChanges="screenLayout|orientation|screenSize
      |keyboard|keyboardHidden|smallestScreenSize" />

2. Annulla WebView ogni volta che la tua app riceve una modifica alla configurazione

Kotlin

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    webView.invalidate()
}

Java

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    webview.invalidate();
}

Questo passaggio si applica solo al sistema di visualizzazione, in quanto Jetpack Compose non ha bisogno di invalidare nulla per ridimensionare correttamente gli elementi Composable. Tuttavia, Compose ricrea spesso un WebView, se non gestito correttamente. Utilizza il wrapper Accompanist WebView per salvare e ripristinare lo stato WebView nelle app Compose.

Risultati

I componenti WebView dell'app ora mantengono il proprio stato e la posizione di scorrimento in più modifiche alla configurazione, dal ridimensionamento alla modifica dell'orientamento, fino alla piegatura e all'apertura.

Risorse aggiuntive

Per scoprire di più sulle modifiche alla configurazione e su come gestirle, vedi Gestire le modifiche alla configurazione.

Gestione dello stato di RecyclerView

Voto: tre stelle

RecyclerView può visualizzare grandi quantità di dati utilizzando il minimo di risorse grafiche. Mentre RecyclerView scorre l'elenco di elementi, l'RecyclerView riutilizza le istanze View degli elementi che sono scorrono sullo schermo per creare nuovi elementi mentre scorrono sullo schermo. Tuttavia, le modifiche alla configurazione, ad esempio la rotazione del dispositivo, possono reimpostare lo stato di RecyclerView, costringendo gli utenti a scorrere di nuovo nella posizione precedente nell'elenco di RecyclerView elementi.

Best practice

RecyclerView deve mantenere il proprio stato, in particolare la posizione di scorrimento, e lo stato degli elementi dell'elenco durante tutte le modifiche alla configurazione.

Ingredienti

Passi

Riepilogo

Imposta il criterio di ripristino dello stato di RecyclerView.Adapter per salvare la posizione di scorrimento di RecyclerView. Salva lo stato di RecyclerView voci dell'elenco. Aggiungi lo stato degli elementi dell'elenco all'adattatore RecyclerView e ripristina lo stato degli elementi dell'elenco quando sono associati a un ViewHolder.

1. Abilita criterio di ripristino dello stato Adapter

Attiva il criterio di ripristino dello stato dell'adattatore RecyclerView in modo che la posizione di scorrimento dell'RecyclerView venga mantenuta per tutte le modifiche alla configurazione. Aggiungi la specifica del criterio al costruttore dell'adattatore:

Kotlin

class MyAdapter() : RecyclerView.Adapter() {
    init {
        stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
    }
    ...
}

Java

class MyAdapter extends RecyclerView.Adapter {

    public Adapter() {
        setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY);
    }
    ...
}

2. Salva lo stato degli elementi dell'elenco stateful

Salva lo stato di elementi di elenco RecyclerView complessi, ad esempio elementi che contengono elementi EditText. Ad esempio, per salvare lo stato di un EditText, aggiungi un callback simile a un gestore onClick per acquisire le modifiche al testo. All'interno del callback, definisci i dati da salvare:

Kotlin

input.addTextChangedListener(
    afterTextChanged = { text ->
        text?.let {
            // Save state here.
        }
    }
)

Java

input.addTextChangedListener(new TextWatcher() {
    
    ...

    @Override
    public void afterTextChanged(Editable s) {
        // Save state here.
    }
});

Dichiara il callback nel tuo Activity o Fragment. Utilizza un ViewModel per archiviare lo stato.

3. Aggiungi lo stato della voce elenco a Adapter

Aggiungi lo stato delle voci dell'elenco a RecyclerView.Adapter. Passa lo stato dell'elemento al costruttore dell'adattatore quando viene creato l'host Activity o Fragment:

Kotlin

val adapter = MyAdapter(items, viewModel.retrieveState())

Java

MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());

4. Recupera lo stato della voce elenco nell'ViewHolder dell'adattatore

In RecyclerView.Adapter, quando associ una ViewHolder a un elemento, ripristina lo stato dell'elemento:

Kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    ...
    val item = items[position]
    val state = states.firstOrNull { it.item == item }

    if (state != null) {
        holder.restore(state)
    }
}

Java

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    ...
    Item item = items[position];
    Arrays.stream(states).filter(state -> state.item == item)
        .findFirst()
        .ifPresent(state -> holder.restore(state));
}

Risultati

Il tuo RecyclerView è ora in grado di ripristinare la sua posizione di scorrimento e lo stato di ogni elemento nell'elenco RecyclerView.

Risorse aggiuntive

Gestione tastiera rimovibile

Voto: tre stelle

Il supporto per le tastiere rimovibili aiuta a massimizzare la produttività degli utenti sui dispositivi con schermi di grandi dimensioni. Android attiva una modifica della configurazione ogni volta che una tastiera viene collegata o scollegata da un dispositivo, il che può causare la perdita dello stato dell'UI. L'app può salvare e ripristinare il proprio stato, consentendo al sistema di gestire la ricreazione delle attività, oppure limitare la ricreazione delle attività per le modifiche alla configurazione della tastiera. In tutti i casi, tutti i dati relativi alla tastiera vengono archiviati in un oggetto Configuration. I campi keyboard e keyboardHidden dell'oggetto di configurazione contengono informazioni sul tipo di tastiera e sulla sua disponibilità.

Best practice

Le app ottimizzate per schermi di grandi dimensioni supportano ogni tipo di dispositivo di input, dalle tastiere software e hardware allo stilo, al mouse, al trackpad e ad altri dispositivi periferici.

Il supporto per le tastiere esterne prevede modifiche alla configurazione, che puoi gestire in due modi:

  1. Consenti al sistema di ricreare l'attività attualmente in esecuzione, dopodiché potrai gestire lo stato dell'app.
  2. Gestisci autonomamente la modifica alla configurazione (l'attività non verrà ricreata):
    • Dichiara tutti i valori di configurazione relativi alla tastiera
    • Creare un gestore delle modifiche alla configurazione

Le app di produttività, che spesso richiedono un controllo preciso dell'interfaccia utente per l'inserimento di testo e altri input, possono trarre vantaggio da un approccio personalizzato alla gestione delle modifiche alla configurazione.

In casi speciali, potresti voler modificare il layout dell'app quando una tastiera hardware è collegata o scollegata, ad esempio per liberare spazio per gli strumenti o per modificare le finestre.

Poiché l'unico modo affidabile per ascoltare le modifiche alla configurazione è eseguire l'override del metodo onConfigurationChanged() di una vista, puoi aggiungere una nuova istanza di View all'attività dell'app e rispondere nel gestore onConfigurationChanged() della visualizzazione alle modifiche alla configurazione causate dal collegamento o dallo scollegamento della tastiera.

Ingredienti

  • android:configChanges: attributo dell'elemento <activity> del file manifest dell'app. Informa il sistema delle modifiche alla configurazione gestite dall'app.
  • View#onConfigurationChanged(): metodo che reagisce alla propagazione di una nuova configurazione dell'app.

Passi

Riepilogo

Dichiara l'attributo configChanges e aggiungi valori relativi alla tastiera. Aggiungi un elemento View alla gerarchia delle visualizzazioni dell'attività e ascolta le modifiche alla configurazione.

1. Dichiara l'attributo configChanges

Aggiorna l'elemento <activity> nel file manifest dell'app aggiungendo i valori keyboard|keyboardHidden all'elenco delle modifiche alla configurazione già gestite:

<activity
      …
      android:configChanges="...|keyboard|keyboardHidden">

2. Aggiungere una visualizzazione vuota alla gerarchia delle visualizzazioni

Dichiara una nuova vista e aggiungi il tuo codice gestore all'interno del metodo onConfigurationChanged() della vista:

Kotlin

val v = object : View(this) {
  override fun onConfigurationChanged(newConfig: Configuration?) {
    super.onConfigurationChanged(newConfig)
    // Handler code here.
  }
}

Java

View v = new View(this) {
    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Handler code here.
    }
};

Risultati

La tua app ora risponderà a una tastiera esterna che viene collegata o scollegata senza ricreare l'attività attualmente in esecuzione.

Risorse aggiuntive

Per scoprire come salvare lo stato della UI dell'app durante le modifiche alla configurazione, ad esempio il collegamento o lo scollegamento della tastiera, consulta l'articolo Salvare gli stati dell'interfaccia utente.