O Android oferece tudo o que você precisa para criar apps de tela grande dignos de notas cinco estrelas. As instruções deste manual mostram e combinam dicas para ajudar você a resolver problemas de desenvolvimento específicos. Cada seção inclui práticas recomendadas, exemplos de códigos de qualidade e orientações detalhadas para ajudar você a tornar seu app ainda melhor.
Notas
As seções estão classificadas por estrelas com base no alinhamento delas com as diretrizes de qualidade de apps para telas grandes.
Atende aos critérios de nível 1, diferenciada para telas grandes | |
Atende aos critérios de nível 2, otimizada para telas grandes | |
Atende aos critérios de nível 3, pronta para telas grandes | |
Fornece alguns recursos de tela grande, mas não atende às diretrizes de qualidade de apps para telas grandes | |
Atende às necessidades de um caso de uso específico, mas não oferece suporte a telas grandes |
Suporte à câmera do Chromebook
Aparece no Google Play para os usuários do Chromebook.
Caso seu app de câmera funcione com os recursos básicos da câmera, não permita que as app stores impeçam que os usuários do Chromebook instalem o app só porque você especificou acidentalmente recursos avançados de câmera encontrados em smartphones de última geração.
Os Chromebooks têm uma câmera frontal integrada (voltada para o usuário) que funciona bem para videoconferências, retratos e outros fins. Porém, nem todos os Chromebooks têm uma câmera traseira (voltada para o mundo), e a maioria das câmeras voltadas para o usuário em Chromebooks não oferecem suporte a foco automático ou flash.
Práticas recomendadas
Apps versáteis de câmera oferecem suporte a todos os dispositivos, independente da configuração da câmera: frontal, traseira ou externa conectada por USB.
Para garantir que as app stores disponibilizem o app para o maior número possível de dispositivos, sempre declare todos os recursos da câmera usados pelo app e indique explicitamente se os recursos são ou não obrigatórios.
Componentes
- Permissão da
CAMERA
: dá ao app acesso às câmeras de um dispositivo. - Elemento de manifesto
<uses-feature>
: informa as app stores sobre os recursos usados pelo app. - Atributo
required
: indica às app stores se o app pode funcionar sem um recurso especificado.
Etapas
Resumo
Declare a permissão CAMERA
. Declare os recursos da câmera que oferecem suporte básico a câmeras. Especifique se cada recurso é obrigatório.
1. Declare a permissão CAMERA
Adicione a permissão abaixo ao manifesto do app:
<uses-permission android:name="android.permission.CAMERA" />
2. Declare as funcionalidades básicas da câmera
Adicione os recursos abaixo ao manifesto do 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. Especifique se cada recurso é obrigatório ou não
Defina android:required="false"
para o recurso android.hardware.camera.any
para permitir que dispositivos que têm qualquer tipo de câmera integrada ou externa (ou nenhuma câmera) possam usar o app.
Para os outros recursos, defina android:required="false"
para garantir que dispositivos, como Chromebooks que não tenham câmeras traseiras, foco automático ou flash possam acessar o aplicativo em app stores.
Resultados
Os usuários de Chromebooks podem fazer o download e instalar o app com o Google Play e outras app stores. Além disso, dispositivos com suporte total a câmeras, como smartphones, não vão ter restrições de funcionalidade.
Ao definir explicitamente os recursos da câmera com suporte do app e especificar os recursos exigidos, você disponibiliza o app para o maior número possível de dispositivos.
Outros recursos
Para mais informações, consulte Recursos de hardware da câmera na documentação de <uses-feature>
.
Orientação restrita do app em smartphones, mas não em dispositivos de tela grande
Como o app funciona muito bem em smartphones na orientação retrato, você o restringiu apenas a esse modo. Mas você percebe uma oportunidade de melhorar o suporte do app em telas grandes na orientação paisagem.
Como você pode aproveitar o melhor de dois mundos, restringindo o app à orientação retrato em telas pequenas, mas ativando o modo paisagem em telas grandes?
Práticas recomendadas
Os melhores apps respeitam as preferências do usuário, como a orientação do dispositivo.
As diretrizes de qualidade de apps para telas grandes recomendam que os apps ofereçam suporte a todas as configurações de dispositivos, incluindo orientações de retrato e paisagem, modo de várias janelas e estados dobrados e desdobrados. Os apps precisam otimizar os layouts e as interfaces do usuário para diferentes configurações e também precisam salvar e restaurar o estado durante as mudanças.
Esta seção apresenta apenas uma medida temporária, oferecendo o mínimo de suporte para telas grandes. Use estas dicas até melhorar o app o suficiente para oferecer suporte total a todas as configurações de dispositivos.
Componentes
screenOrientation
: configuração do manifesto do app que permite especificar como o aplicativo responde às mudanças de orientação do dispositivo.- Jetpack WindowManager: conjunto de bibliotecas que permitem determinar o tamanho e a proporção da janela do app. compatível com versões anteriores do nível 14 da API
Activity#setRequestedOrientation()
: método com que é possível mudar a orientação do app no momento da execução.
Etapas
Resumo
Ativa o app para processar mudanças de orientação por padrão no manifesto dele. Durante a execução, determine o tamanho da janela do app. Se a janela do app for pequena, restrinja a orientação do app substituindo a configuração de orientação no manifesto.
1. Especificar a configuração de orientação no manifesto do app
Você pode evitar declarar o elemento screenOrientation
do manifesto do app, o que define a orientação padrão como unspecified
, ou pode definir a orientação da tela como fullUser
. Se o usuário não tiver bloqueado a rotação com base no sensor, o app vai oferecer suporte a todas as orientações do dispositivo.
<activity
android:name=".MyActivity"
android:screenOrientation="fullUser">
A diferença entre usar unspecified
e fullUser
é sutil, mas importante. Se você não declarar um valor screenOrientation
, o sistema vai escolher a orientação, e a política usada para defini-la poderá variar de acordo com o dispositivo. Por outro lado, a especificação de fullUser
corresponde melhor ao comportamento que o usuário definiu para o dispositivo: se ele bloqueou a rotação com base no sensor, o app segue a preferência do usuário. Caso contrário, o sistema permite qualquer uma das quatro orientações de tela possíveis (retrato, paisagem, retrato invertido ou paisagem invertida). Consulte android:screenOrientation
.
2. Determinar o tamanho da tela
Com o manifesto definido para oferecer suporte a todas as orientações permitidas pelo usuário, você pode especificar a orientação do app de forma programática com base no tamanho da tela.
Adicione as bibliotecas do Jetpack WindowManager ao arquivo build.gradle
ou build.gradle.kts
do módulo:
Kotlin
implementation("androidx.window:window:version
") implementation("androidx.window:window-core:version
")
Groovy
implementation 'androidx.window:window:version
' implementation 'androidx.window:window-core:version
'
Use o método Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics()
para conferir o tamanho da tela do dispositivo como um objeto WindowMetrics
. As métricas da janela podem ser comparadas a classes de tamanho de janela para decidir quando restringir a orientação.
As classes de tamanho de janelas oferecem os pontos de interrupção entre telas pequenas e grandes.
Use os pontos de interrupção WindowWidthSizeClass#COMPACT
e WindowHeightSizeClass#COMPACT
para determinar o tamanho da tela:
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; }
- Observação:
- Os exemplos acima são implementados como métodos de uma atividade. A atividade é desreferenciada como
this
no argumento decomputeMaximumWindowMetrics()
. - O método
computeMaximumWindowMetrics()
é usado em vez decomputeCurrentWindowMetrics()
porque o app pode ser iniciado no modo de várias janelas, o que ignora a configuração de orientação da tela. Não há sentido em determinar o tamanho da janela do app e substituir a configuração de orientação, a menos que a janela do app seja a tela inteira do dispositivo.
Consulte WindowManager para instruções sobre como declarar dependências e disponibilizar o método computeMaximumWindowMetrics()
no app.
3. Substituir a configuração do manifesto do app
Se você determinar que o dispositivo tem um tamanho de tela compacto, chame Activity#setRequestedOrientation()
para substituir a configuração screenOrientation
do manifesto:
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); } } }); }
Ao adicionar a lógica aos métodos onCreate()
e View.onConfigurationChanged()
, você poderá acessar as métricas máximas da janela e substituir a configuração de orientação sempre que a atividade for redimensionada ou movida entre as telas, por exemplo, após uma rotação do dispositivo ou quando um dispositivo dobrável for dobrado ou desdobrado.
Para mais informações sobre quando as mudanças de configuração ocorrem e quando elas causam a recriação de atividades, consulte Gerenciar mudanças de configuração.
Resultados
Agora, o app vai permanecer na orientação retrato em telas pequenas, independente da rotação do dispositivo. Em telas grandes, o app precisa oferecer suporte às orientações de paisagem e retrato.
Outros recursos
Para receber ajuda com o upgrade do app para que ele ofereça suporte a todas as configurações de dispositivos o tempo todo, consulte:
- Suporte a tamanhos de tela diferentes
- Gerenciar mudanças de configuração
- Salvar estados da interface
Pausar e retomar a reprodução de mídia usando a barra de espaço do teclado externo
A otimização para telas grandes inclui a capacidade de processar entradas do teclado externo, como usar o pressionamento da barra de espaço para pausar ou retomar a reprodução de vídeos e outras mídias. Isso é especialmente útil para tablets, que geralmente se conectam a teclados externos, e para Chromebooks, que geralmente vêm com teclados externos, mas podem ser usados no modo tablet.
Quando a mídia é o único elemento da janela (por exemplo, uma reprodução de vídeo em tela cheia), responda a eventos de pressionamento de tecla no nível da atividade ou no nível da tela, no caso do Jetpack Compose.
Práticas recomendadas
Sempre que seu app reproduzir um arquivo de mídia, os usuários poderão pausar e retomar a reprodução pressionando a barra de espaço em um teclado físico.
Componentes
KEYCODE_SPACE
: constante de código de tecla da barra de espaço.
Compose
onPreviewKeyEvent
: oModifier
que permite a um componente interceptar eventos de teclas do hardware quando ele ou um dos filhos está em foco.onKeyEvent
: semelhante aoonPreviewKeyEvent
, esseModifier
permite que um componente intercepte eventos de teclas do hardware quando ele ou um dos filhos está em foco.
Visualizações
onKeyUp()
: chamado quando uma tecla é liberada e não é processada por uma visualização em uma atividade.
Etapas
Resumo
Apps baseados no Jetpack Compose ou em visualizações respondem a pressionamentos de tecla de maneiras semelhantes: o app precisa detectar eventos de pressionamento de tecla, filtrá-los e responder a pressionamentos selecionados, como o de uma barra de espaço.
1. Detectar eventos de teclado
Visualizações
Em uma atividade no app, substitua o método onKeyUp()
:
Kotlin
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { ... }
Java
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { ... }
O método é invocado sempre que uma tecla pressionada é solta. Portanto, ele é acionado exatamente uma vez para cada tecla pressionada.
Compose
Com o Jetpack Compose, você pode usar os modificadores onPreviewKeyEvent
ou onKeyEvent
na tela que gerencia o pressionamento de tecla:
Column(modifier = Modifier.onPreviewKeyEvent { event ->
if (event.type == KeyEventType.KeyUp) {
...
}
...
})
ou
Column(modifier = Modifier.onKeyEvent { event ->
if (event.type == KeyEventType.KeyUp) {
...
}
...
})
2. Filtrar pressionamentos da barra de espaço
No método onKeyUp()
ou nos métodos modificadores onPreviewKeyEvent
e onKeyEvent
do Compose, filtre por KeyEvent.KEYCODE_SPACE
para enviar o evento correto ao componente de mídia:
Visualizações
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) {
...
}
...
})
ou
Column(modifier = Modifier.onKeyEvent { event ->
if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
...
}
...
})
Resultados
Seu app agora pode responder a pressionamentos de tecla da barra de espaço para pausar e retomar um vídeo ou outra mídia.
Outros recursos
Para saber mais sobre os eventos de teclado e como gerenciá-los, consulte Gerenciar a entrada do teclado.
Rejeição da palma ao usar a stylus
Uma stylus pode ser uma ferramenta muito produtiva e criativa em telas grandes. No entanto, quando os usuários desenham, escrevem ou interagem com o app usando uma stylus, às vezes eles tocam na tela com a palma da mão. O evento de toque pode ser informado ao app antes que o sistema reconheça e desconsidere o evento como um toque acidental da palma da mão.
Práticas recomendadas
O app precisa identificar e ignorar eventos de toque irrelevantes. O Android cancela um toque da palma da mão enviando um objeto MotionEvent
. Procure ACTION_CANCEL
ou ACTION_POINTER_UP
e FLAG_CANCELED
no objeto para determinar se o gesto causado pelo toque da palma da mão será rejeitado.
Componentes
MotionEvent
: representa eventos de toque e movimento. Contém as informações necessárias para determinar se um evento será desconsiderado ou não.OnTouchListener#onTouch()
: recebe objetosMotionEvent
.MotionEvent#getActionMasked()
: retorna a ação associada a um evento de movimento.ACTION_CANCEL
: constanteMotionEvent
que indica que um gesto precisa ser desfeito.ACTION_POINTER_UP
: constanteMotionEvent
que indica que um ponteiro diferente do primeiro foi levantado, ou seja, parou de fazer contato com a tela do dispositivo.FLAG_CANCELED
: constanteMotionEvent
que indica que o ponteiro que foi levantado causou um evento de toque não intencional. Adicionado aos eventosACTION_POINTER_UP
eACTION_CANCEL
no Android 13 (nível 33 da API) e mais recentes.
Etapas
Resumo
Examine objetos MotionEvent
enviados para seu app. Use as APIs MotionEvent
para determinar as características do evento:
- Eventos de ponteiro único: procure
ACTION_CANCEL
. No Android 13 e mais recentes, procure também porFLAG_CANCELED
. - Eventos com vários ponteiros: no Android 13 e mais recentes, procure
ACTION_POINTER_UP
eFLAG_CANCELED
.
Responda a eventos ACTION_CANCEL
e ACTION_POINTER_UP
/FLAG_CANCELED
.
1. Obter objetos de eventos de movimento
Adicione um OnTouchListener
ao 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. Determinar a ação e as flags do evento
Procure ACTION_CANCEL
, que indica um evento de ponteiro único em todos os níveis de API. No Android 13 e mais recentes, procure ACTION_POINTER_UP
em 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. Desfazer o gesto
Depois de identificar um toque da palma da mão, você pode desfazer os efeitos do gesto na tela.
O app precisa manter um histórico de ações do usuário para que entradas não intencionais, como toques da palma da mão, possam ser desfeitas. Consulte Implementar um app de desenho básico no codelab Melhorar o suporte à stylus em um app Android para conferir um exemplo.
Resultados
O app agora pode identificar e rejeitar toques da palma da mão em eventos de vários ponteiros no Android 13 e níveis da API mais recentes e em eventos de ponteiro único em todos os níveis da API.
Outros recursos
Para mais informações, consulte os tópicos abaixo:
- Recursos e APIs do Android 13: Rejeição da palma aprimorada
- Guias para desenvolvedores
- Codelab: Melhorar o suporte à stylus em um app Android
Gerenciamento de estado do WebView
O WebView
é um componente usado com frequência e que oferece um sistema avançado para gerenciamento de estado. O WebView
precisa manter o estado e a posição de rolagem durante as mudanças de configuração. Um WebView
pode perder a posição de rolagem quando o usuário gira o dispositivo ou desdobra um smartphone dobrável, o que força o usuário a rolar novamente da parte de cima do WebView
para a posição de rolagem anterior.
Práticas recomendadas
Minimize o número de vezes que um WebView
é recriado. O WebView
é bom em gerenciar o estado, e você pode aproveitar essa qualidade gerenciando o maior número possível de mudanças de configuração. Seu app precisa processar mudanças de configuração, porque a recriação da Activity
(a maneira como o sistema processa essas mudanças) também recria o WebView
, o que faz com que o WebView
perca o estado.
Componentes
android:configChanges
: atributo do elemento<activity>
do manifesto. Lista as mudanças de configuração gerenciadas pela atividade.View#invalidate()
: método que faz com que uma visualização seja redesenhada. Herdado peloWebView
.
Etapas
Resumo
Para salvar o estado do WebView
, evite ao máximo a recriação da Activity
e deixe o WebView
ser invalidado para que possa ser redimensionado, mantendo o estado.
1. Adicionar mudanças de configuração ao arquivo AndroidManifest.xml
do app
Para evitar a recriação de atividades, especifique as mudanças de configuração processadas pelo app, e não pelo sistema:
<activity
android:name=".MyActivity"
android:configChanges="screenLayout|orientation|screenSize
|keyboard|keyboardHidden|smallestScreenSize" />
2. Invalidar o WebView
sempre que o app receber uma mudança de configuração
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) webView.invalidate() }
Java
@Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); webview.invalidate(); }
Esta etapa se aplica apenas ao sistema de visualização, já que o Jetpack Compose não precisa invalidar nada para redimensionar corretamente os elementos Composable
. No entanto, o Compose recria um WebView
com frequência quando ele não é gerenciado corretamente. Use o wrapper Accompanist WebView para salvar e restaurar o estado do WebView
nos apps do Compose.
Resultados
Os componentes do WebView
do app agora mantêm o estado e a posição de rolagem em várias mudanças de configuração, desde o redimensionamento e mudança de orientação até a dobra e o desdobramento.
Outros recursos
Para saber mais sobre as mudanças de configuração e como elas são gerenciadas, consulte Gerenciar mudanças de configuração.
Gerenciamento de estado da RecyclerView
A RecyclerView
pode mostrar grandes quantidades de dados usando o mínimo de recursos gráficos. À medida que uma RecyclerView
rola a lista de itens, ela reutiliza as instâncias de View
dos itens que rolaram para fora da tela e cria novos itens conforme eles aparecem. No entanto, mudanças de configuração, como a rotação do dispositivo, podem redefinir o estado de uma RecyclerView
, forçando os usuários a rolar novamente para a posição anterior na lista de itens da RecyclerView
.
Práticas recomendadas
A RecyclerView
precisa manter o estado, principalmente a posição de rolagem, e o estado dos elementos da lista durante todas as mudanças de configuração.
Componentes
RecyclerView.Adapter#setStateRestorationPolicy()
: especifica como umaRecyclerView.Adapter
restaura o estado após uma mudança de configuração.ViewModel
: mantém o estado de uma atividade ou um fragmento.
Etapas
Resumo
Defina a política de restauração de estado da RecyclerView.Adapter
para salvar a posição de rolagem da RecyclerView
. Salve o estado dos itens da lista da RecyclerView
. Adicione o estado desses itens ao adaptador da RecyclerView
e restaure o estado quando eles estiverem vinculados a um ViewHolder
.
1. Ativar a política de restauração de estado do Adapter
Ative a política de restauração de estado do adaptador da RecyclerView
para que a posição de rolagem da RecyclerView
seja mantida durante as mudanças de configuração. Adicione a especificação da política ao construtor do adaptador:
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. Salvar o estado dos itens da lista com estado
Salve o estado de itens complexos da lista da RecyclerView
, como aqueles que contêm elementos EditText
. Por exemplo, se quiser salvar o estado de uma EditText
, adicione um callback semelhante a um gerenciador onClick
para capturar mudanças de texto. No callback, defina quais dados serão salvos:
Kotlin
input.addTextChangedListener( afterTextChanged = { text -> text?.let { // Save state here. } } )
Java
input.addTextChangedListener(new TextWatcher() { ... @Override public void afterTextChanged(Editable s) { // Save state here. } });
Declare o callback na Activity
ou no Fragment
. Use um ViewModel
para armazenar o estado.
3. Adicionar o estado dos itens da lista ao Adapter
Adicione o estado dos itens da lista a RecyclerView.Adapter
. Transmita o estado do item ao construtor do adaptador quando a Activity
ou o Fragment
do host forem criados:
Kotlin
val adapter = MyAdapter(items, viewModel.retrieveState())
Java
MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());
4. Recuperar o estado dos itens da lista no ViewHolder
do adaptador
Na RecyclerView.Adapter
, restaure o estado de um item ao vincular um ViewHolder
a ele:
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)); }
Resultados
A RecyclerView
agora pode restaurar a posição de rolagem e o estado de cada item na lista da RecyclerView
.
Outros recursos
Gerenciamento de teclado destacável
O suporte a teclados removíveis ajuda a maximizar a produtividade do usuário em dispositivos
e dispositivos de tela. O Android aciona uma mudança de configuração sempre que um teclado é
anexados ou desconectados de um dispositivo, o que pode causar uma perda do estado da interface. Seu
pode salvar e restaurar o estado, permitindo que o sistema manipule
recriação de atividades ou restringir a recriação de atividades para mudanças de configuração do teclado.
Em todos os casos, todos os dados relacionados ao teclado são armazenados em um
Objeto Configuration
. Os métodos keyboard
e
Os campos keyboardHidden
do objeto de configuração contêm informações sobre o tipo
do teclado e sua disponibilidade.
Práticas recomendadas
Apps otimizados para telas grandes oferecem suporte a todos os tipos de dispositivos de entrada, desde teclados de hardware e software para stylus, mouse, trackpad e outros periféricos dispositivos.
O suporte a teclados externos envolve mudanças de configuração, que você pode gerenciar de duas maneiras:
- Deixe o sistema recriar a atividade em execução no momento e você cuidará do gerenciamento do estado do app.
- Gerencie a mudança de configuração por conta própria (a atividade não será recriada):
- Declarar todos os valores de configuração relacionados ao teclado
- Criar um gerenciador de mudanças de configuração
Aplicativos de produtividade, que geralmente exigem um controle preciso da interface para entrada de texto e outras entradas, pode se beneficiar da abordagem do tipo "aprenda a fazer" para lidar com mudanças na configuração.
Em casos especiais, você pode querer alterar o layout do aplicativo quando um hardware quando o teclado está conectado ou desconectado, por exemplo, para liberar mais espaço para ferramentas ou janelas de edição.
Como a única maneira confiável de detectar alterações de configuração é modificar
método onConfigurationChanged()
de uma visualização, você pode adicionar uma nova
instância à sua atividade no app e responder no onConfigurationChanged()
da visualização.
para alterações de configuração causadas pelo teclado que está sendo conectado ou
separada.
Componentes
android:configChanges
: atributo do elemento<activity>
do manifesto do app. Informa o sistema sobre mudanças de configuração que o app gerencia.View#onConfigurationChanged()
: método que reage à propagação de uma nova configuração do app.
Etapas
Resumo
Declare o atributo configChanges
e adicione valores relacionados ao teclado. Adicione um
Use View
na hierarquia de visualização da atividade e detecte mudanças de configuração.
1. Declarar o atributo configChanges
Atualize o elemento <activity>
no manifesto do app adicionando os valores keyboard|keyboardHidden
à lista de mudanças de configuração já gerenciadas:
<activity
…
android:configChanges="...|keyboard|keyboardHidden">
2. Adicionar uma visualização vazia à hierarquia de visualização
Declare uma nova visualização e adicione o código do gerenciador ao método onConfigurationChanged()
da visualização:
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. } };
Resultados
Agora, seu app responderá a um teclado externo que está sendo conectado ou desconectado sem recriar a atividade em execução no momento.
Outros recursos
Para saber como salvar o estado da interface do seu app durante mudanças de configuração, como conexão ou remoção do teclado, consulte Salvar estados da interface.
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Gerenciar mudanças de configuração