Supporta schermi di dimensioni diverse

Il supporto di schermi di dimensioni diverse consente l'accesso alla tua app da parte della più vasta gamma di dispositivi e del maggior numero di utenti.

Per supportare il maggior numero possibile di dimensioni dello schermo, progetta i tuoi layout dell'app in modo che siano reattivi e adattivi. I layout adattabili/adattivi offrono un'esperienza utente ottimizzata indipendentemente dalle dimensioni dello schermo, consentendo all'app di supportare telefoni, tablet, pieghevoli, dispositivi ChromeOS, orientamenti verticale e orizzontale e configurazioni ridimensionabili come la modalità multi-finestra.

Classi di dimensioni della finestra

Le classi di dimensioni delle finestre sono un insieme di punti di interruzione dell'area visibile con i comandi vocali che ti aiutano a progettare, sviluppare e testare i layout adattabili/adattivi. I punti di interruzione bilanciano la semplicità del layout con la flessibilità di ottimizzare l'app per casi unici.

Le classi di dimensioni della finestra classificano l'area di visualizzazione disponibile per la tua app in compatta, media o espansa. La larghezza e l'altezza disponibili sono classificate separatamente. Di conseguenza, in qualsiasi momento la tua app prevede due classi di dimensioni delle finestre: una per la larghezza e una per l'altezza. In genere la larghezza disponibile è più importante dell'altezza disponibile a causa dell'ubiquità dello scorrimento verticale, pertanto la classe delle dimensioni della finestra della larghezza è probabilmente più pertinente per l'UI della tua app.

Figura 1. Rappresentazioni di classi di dimensioni delle finestre basate sulla larghezza.
Figura 2. Rappresentazioni di classi di dimensioni delle finestre basate sull'altezza.

Come mostrati nelle figure, i punti di interruzione consentono di continuare a pensare ai layout in termini di dispositivi e configurazioni. Ogni punto di interruzione della classe di dimensione rappresenta un caso tipico degli scenari tipici dei dispositivi e può essere un utile punto di riferimento per la progettazione dei layout basati sui punti di interruzione.

Classe dimensioni Punto di interruzione Rappresentazione del dispositivo
Larghezza compatta larghezza < 600 dp 99,96% degli smartphone in verticale
Larghezza media 600 dp ≤ larghezza < 840 dp il 93,73% dei tablet in verticale,

più grandi display interni aperti in verticale

Larghezza espansa larghezza ≥ 840 dp il 97,22% dei tablet in orizzontale,

più grandi display interni aperti in orizzontale

Altezza compatta Altezza < 480 dp 99,78% degli smartphone in orizzontale
Altezza media 480 dp ≤ altezza < 900 dp il 96,56% dei tablet in orizzontale,

97,59% degli smartphone in verticale

Altezza espansa altezza ≥ 900 dp 94,25% dei tablet in verticale

Sebbene possa essere utile visualizzare le classi di dimensioni come dispositivi fisici, le classi di dimensioni delle finestre non sono esplicitamente determinate dalle dimensioni dello schermo dei dispositivi. Le classi di dimensioni delle finestre non sono destinate alla logica di tipo isTablet. Al contrario, le classi di dimensioni delle finestre sono determinate dalle dimensioni delle finestre disponibili per l'applicazione, indipendentemente dal tipo di dispositivo su cui è in esecuzione, il che ha due importanti implicazioni:

  • I dispositivi fisici non garantiscono una specifica classe di dimensioni delle finestre. Lo spazio disponibile sullo schermo per l'app può essere diverso dalle dimensioni dello schermo del dispositivo per diversi motivi. Sui dispositivi mobili, la modalità schermo diviso può suddividere lo schermo tra due applicazioni. Su ChromeOS, le app Android possono essere presentate in finestre in formato libero ridimensionabili in modo arbitrario. I dispositivi pieghevoli possono avere due schermi di diverse dimensioni accessibili singolarmente piegando o aprendo il dispositivo.

  • La classe delle dimensioni della finestra può cambiare per tutta la durata dell'app. Mentre l'app è in esecuzione, i cambiamenti di orientamento del dispositivo, il multitasking e la possibilità di piegare/apertura possono cambiare la quantità di spazio disponibile sullo schermo. Di conseguenza, la classe delle dimensioni della finestra è dinamica e l'UI della tua app dovrebbe adattarsi di conseguenza.

Le classi di dimensioni delle finestre vengono mappate ai punti di interruzione del layout nella griglia di layout adattabile di Material Design. Utilizza le classi di dimensioni delle finestre per prendere decisioni generali sul layout dell'applicazione, ad esempio per decidere se usare un layout canonico specifico per sfruttare ulteriore spazio sullo schermo.

Puoi calcolare l'attuale WindowSizeClass utilizzando la funzione WindowSizeClass#compute() fornita dalla libreria Jetpack WindowManager. Di seguito è riportato un esempio di come calcolare la classe di dimensioni della finestra e ricevere aggiornamenti ogni volta che la classe di dimensioni della finestra cambia:

Kotlin

class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ...

        // 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)
                computeWindowSizeClasses()
            }
        })

        computeWindowSizeClasses()
    }

    private fun computeWindowSizeClasses() {
        val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
        val width = metrics.bounds.width()
        val height = metrics.bounds.height()
        val density = resources.displayMetrics.density
        val windowSizeClass = WindowSizeClass.compute(width/density, height/density)
        // COMPACT, MEDIUM, or EXPANDED
        val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass
        // COMPACT, MEDIUM, or EXPANDED
        val heightWindowSizeClass = windowSizeClass.windowHeightSizeClass

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

Java

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        // 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);
                computeWindowSizeClasses();
            }
        });

        computeWindowSizeClasses();
    }

    private void computeWindowSizeClasses() {
        WindowMetrics metrics = WindowMetricsCalculator.getOrCreate()
                .computeCurrentWindowMetrics(this);

        int width = metrics.getBounds().width
        int height = metrics.getBounds().height()
        float density = getResources().getDisplayMetrics().density;
        WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density)
        // COMPACT, MEDIUM, or EXPANDED
        WindowWidthSizeClass widthWindowSizeClass = windowSizeClass.getWindowWidthSizeClass()
        // COMPACT, MEDIUM, or EXPANDED
        WindowHeightSizeClass heightWindowSizeClass = windowSizeClass.getWindowHeightSizeClass()

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

Dopo aver osservato le classi delle dimensioni delle finestre nella tua app, puoi iniziare a modificare il layout in base alla classe attuale delle dimensioni delle finestre.

Layout e classi di dimensioni delle finestre

Man mano che apporti le modifiche al layout, testane il comportamento in tutte le dimensioni delle finestre, soprattutto in base alle larghezze dei punti di interruzione compatte, medie ed espanse.

Se già disponi di un layout per schermi compatti, ottimizzalo per la classe delle dimensioni della larghezza espansa, poiché questa classe di dimensioni offre più spazio per ulteriori modifiche ai contenuti e all'interfaccia utente. Quindi decidi quale layout è più appropriato per la classe di larghezza media; valuta la possibilità di aggiungere un layout specializzato.

Passaggi successivi

Per scoprire di più su come utilizzare le classi di dimensioni delle finestre per creare layout adattabili/adattivi, consulta quanto segue:

Per scoprire di più su ciò che rende un'app perfetta su tutti i dispositivi e su schermi di tutte le dimensioni, consulta: