Compatibilidade com diferentes tamanhos de tela

O suporte a diferentes tamanhos de tela permite que o app seja acessado pela maior variedade de dispositivos e usuários possível.

Para oferecer suporte ao máximo possível de tamanhos de tela, crie layouts de app responsivos e adaptáveis. Os layouts responsivos/adaptáveis proporcionam uma experiência do usuário otimizada, independente do tamanho da tela. Isso permite que o app acomode smartphones, tablets, dobráveis, dispositivos ChromeOS, orientações de retrato e paisagem e configurações redimensionáveis como o modo de várias janelas.

Classes de tamanho de janela

As classes de tamanho de janela são um conjunto de pontos de interrupção específicos que ajudam você a projetar, desenvolver e testar layouts responsivos/adaptáveis. Os pontos de interrupção equilibram a simplicidade do layout com a flexibilidade de otimizar o app para casos únicos.

As classes de tamanho da janela categorizam a área de exibição disponível ao app como compacta, média ou expandida. A largura e a altura disponíveis são classificadas separadamente. A todo momento, o app tem duas classes de tamanho de janela: uma para largura e outra para altura. A largura disponível geralmente é mais importante que a altura disponível devido à onipresença da rolagem vertical. Portanto, a classe de tamanho da janela de largura provavelmente é mais relevante para a interface do app.

Figura 1. Representações de classes de tamanho de janela baseadas em largura.
Figura 2. Representações de classes de tamanho de janela baseadas em altura.

Conforme ilustrado nas figuras, os pontos de interrupção permitem que você continue pensando nos layouts em termos de dispositivos e configurações. Cada ponto de interrupção de classe de tamanho representa um caso majoritário para cenários de dispositivos típicos e podem ser uma referência útil enquanto você pensa sobre o design dos seus layouts baseados em pontos de interrupção.

Classe de tamanho Ponto de interrupção Representação do dispositivo
Largura compacta largura < 600 dp 99,96% dos smartphones no modo retrato
Largura média 600 dp ≤ largura < 840 dp 93,73% dos tablets no modo retrato

a maioria das telas internas grandes desdobradas no modo retrato

Largura expandida largura ≥ 840 dp 97,22% dos tablets no modo paisagem

a maioria das telas internas desdobradas no modo paisagem

Altura compacta altura < 480 dp 99,78% dos smartphones no modo paisagem
Altura média 480 dp ≤ altura < 900 dp 96,56% dos tablets no modo paisagem

97,59% de smartphones no modo retrato

Altura expandida altura ≥ 900 dp 94,25% de tablets no modo retrato

Embora visualizar classes de tamanho como dispositivos físicos possa ser útil, as classes de tamanho de janela não são explicitamente determinadas pelo tamanho da tela do dispositivo. As classes de tamanho de janela não se destinam à lógica do tipo isTablet. Em vez disso, as classes de tamanho de janela são determinadas pelo tamanho da janela disponível para o aplicativo, independentemente do tipo de dispositivo em que o app está sendo executado, o que tem duas implicações importantes:

  • Os dispositivos físicos não garantem uma classe de tamanho de janela específica. O espaço na tela disponível para o app pode ser diferente do tamanho da tela do dispositivo por vários motivos. Em dispositivos móveis, o modo de tela dividida pode dividir a tela entre dois aplicativos. No ChromeOS, os apps Android podem ser apresentados em janelas de formato livre e redimensionáveis arbitrariamente. Os dobráveis podem ter duas telas de tamanho diferente, acessadas individualmente ao dobrar ou desdobrar o dispositivo.

  • A classe de tamanho de janela pode mudar durante todo o ciclo de vida do app. Enquanto ele está em execução, a orientação, multitarefas e dobrar/desdobrar o dispositivo podem mudar a quantidade de espaço disponível na tela. Como resultado, a classe de tamanho da janela é dinâmica, e a interface do app precisa se adaptar de acordo com ela.

As classes de tamanho de janela mapeiam para os pontos de interrupção do layout na grade de layout responsivo (link em inglês) do Material Design. Use classes de tamanho de janela para tomar decisões importantes sobre o layout do aplicativo, como decidir se é necessário usar um layout canônico específico para aproveitar o espaço adicional na tela.

É possível calcular o WindowSizeClass atual usando a função WindowSizeClass#compute() fornecida pela biblioteca Jetpack WindowManager. Confira a seguir um exemplo de como calcular a classe de tamanho da janela e receber atualizações sempre que ela mudar:

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.
    }
}

Quando estiver observando as classes de tamanho de janela no app, você vai estar pronto para começar a mudar o layout com base na classe de tamanho de janela atual.

Layouts e classes de tamanho de janela

Ao fazer mudanças no layout, teste o comportamento dele em todos os tamanhos de janela, especialmente nas larguras de ponto de interrupção compacta, média e expandida.

Se você já tem um layout para telas compactas, primeiro otimize o layout para a classe de tamanho de largura expandida, já que essa classe oferece mais espaço para conteúdo adicional e mudanças na interface. Em seguida, decida qual layout faz sentido para a classe de tamanho de largura média e considere adicionar um layout especializado.

Próximas etapas

Para saber mais sobre como usar classes de tamanho de janela para criar layouts responsivos/adaptáveis, consulte:

Para saber mais sobre o que faz um app funcionar bem em todos os dispositivos e tamanhos de tela, consulte: