Definir layouts no Wear

Os apps Wear OS usam as mesmas técnicas de layout dos dispositivos Android portáteis, mas precisam ser projetados com restrições específicas. Não espere uma boa experiência ao transferir a funcionalidade e a IU de um app para celular.

Para mais informações sobre como projetar ótimos apps para wearables, leia as Diretrizes de design do Wear OS.

Ao criar layouts para apps Wear OS, é preciso levar em conta dispositivos com telas quadradas e redondas. O conteúdo próximo aos cantos da tela pode ser cortado em dispositivos Wear OS redondos. Portanto, os layouts projetados para telas quadradas podem ter problemas de exibição em dispositivos redondos.

Por exemplo, a Figura 1 mostra como o layout a seguir aparece em telas quadradas e redondas:

Figura 1. Demonstração de como um layout projetado para telas quadradas não funciona bem em telas redondas.

Assim, se você usar as seguintes configurações no seu layout, o texto não será exibido corretamente em dispositivos com telas redondas:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        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="@string/hello_square" />
    </LinearLayout>
    

Há duas abordagens para resolver esse problema:

  1. Usar layouts na Biblioteca de IU do Wear para dispositivos quadrados e redondos.
    • BoxInsetLayout: esse layout aplica diferentes inserções de janela, dependendo do formato da tela do dispositivo. Use essa abordagem quando quiser usar um layout semelhante nos dois formatos de tela sem que as visualizações sejam cortadas perto das bordas das telas redondas.
    • Layout curvo: use esse layout quando quiser exibir e manipular uma lista vertical de itens otimizados para telas redondas.
  2. Fornecer recursos de layout alternativos para dispositivos quadrados e redondos, conforme descrito no guia Fornecimento de recursos. No momento da execução, o Wear detecta o formato da tela do dispositivo e carrega o layout correto.

Para compilar um projeto do Android Studio com essa biblioteca, verifique se o pacote Extras > Google Repository está instalado no Android SDK Manager. Além disso, inclua as seguintes dependências no arquivo build.gradle do seu módulo wear:

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:wear:26.0.0'
    }
    

Usar um BoxInsetLayout

Figura 2. Inserções de janela em uma tela redonda.

A classe BoxInsetLayout da Biblioteca de IU do Wear permite definir um único layout que funcione para telas quadradas e redondas. Essa classe aplica as inserções de janela necessárias, dependendo do formato da tela, e permite alinhar facilmente as visualizações no centro ou perto das bordas da tela.

Observação: a classe BoxInsetLayout substitui uma classe obsoleta semelhante na Biblioteca de Suporte de Wearables.

O quadrado cinza da Figura 2 mostra a área em que o BoxInsetLayout pode colocar automaticamente as visualizações filhas em telas redondas depois de aplicar as inserções de janela necessárias. Para serem exibidas dentro dessa área, as visualizações filhas especificam o atributo boxedEdges com os seguintes valores:

  • Uma combinação de top, bottom, left e right. Por exemplo, um valor "left|top" posiciona as bordas esquerda e superior da visualização filha dentro do quadrado cinza na Figura 2.
  • O valor "all" posiciona todo o conteúdo da visualização filha dentro do quadrado cinza na Figura 2.

Em telas quadradas, as inserções da janela são zero e o atributo boxedEdges é ignorado.

Figura 3. Uma definição de layout que funciona em telas quadradas e redondas.

O layout mostrado na Figura 3 usa o elemento <BoxInsetLayout> e funciona em telas quadradas e redondas:

    <android.support.wear.widget.BoxInsetLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:padding="15dp">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="5dp"
            app:boxedEdges="all">

            <TextView
                android:gravity="center"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                android:text="@string/sometext"
                android:textColor="@color/black" />

            <ImageButton
                android:background="@null"
                android:layout_gravity="bottom|left"
                android:layout_height="50dp"
                android:layout_width="50dp"
                android:src="@drawable/ok" />

            <ImageButton
                android:background="@null"
                android:layout_gravity="bottom|right"
                android:layout_height="50dp"
                android:layout_width="50dp"
                android:src="@drawable/cancel" />
        </FrameLayout>
    </android.support.wear.widget.BoxInsetLayout>
    

Observe as partes do layout marcadas em negrito:

  • android:padding="15dp"

    Essa linha atribui preenchimento ao elemento <BoxInsetLayout>. As inserções de janelas em dispositivos redondos são maiores que 15 dp, então esse preenchimento se aplica somente a telas quadradas.

  • android:padding="5dp"

    Essa linha atribui preenchimento ao elemento FrameLayout interno. Esse preenchimento se aplica a telas quadradas e redondas. O preenchimento total entre os botões e as inserções de janela é de 20 dp em telas quadradas (15 + 5) e 5 dp em telas redondas.

  • app:boxedEdges="all"

    Essa linha garante que o elemento FrameLayout e os filhos dele sejam encaixados dentro da área definida pelas inserções de janela nas telas redondas. Essa linha não tem efeito nas telas quadradas.

Usar um layout curvo

A classe WearableRecyclerView da Biblioteca de IU do Wear permite ativar um layout curvo, otimizado para telas redondas. Para ativar um layout curvo para listas roláveis no seu app, consulte Criar um layout curvo.

Usar layouts diferentes para telas quadradas e redondas

Um dispositivo Wear pode ter uma tela quadrada ou redonda. Seu app precisa ser compatível com as duas configurações de dispositivo. Para isso, é preciso fornecer recursos alternativos. Aplique os qualificadores de recursos -round e -notround a layouts, dimensões ou outros tipos de recursos.

Por exemplo, considere organizar layouts da seguinte maneira:

  • O diretório layout/ contém layouts que funcionam para smartwatches circulares e quadrados.
  • Os diretórios layout-round/ e layout-notround/ contêm layouts específicos para o formato de uma tela.

Você também pode usar os diretórios de recursos res/values, res/values-round e res/values-notround. Ao organizar recursos dessa maneira, você pode compartilhar um único layout alterando somente atributos específicos, com base no tipo de dispositivo.

Variar os valores

Uma maneira fácil de compilar para smartwatches redondos e quadrados é usando values/dimens.xml e values-round/dimens.xml. Ao especificar diferentes configurações de preenchimento, você pode criar o seguinte layout com um único arquivo layout.xml e os dois arquivos dimens.xml:

    <dimen name="header_start_padding">36dp</dimen>
    <dimen name="header_end_padding">22dp</dimen>
    <dimen name="list_start_padding">36dp</dimen>
    <dimen name="list_end_padding">22dp</dimen>
    
Uso de values-round/dimens.xml

Figura 4. Uso de values-round/dimens.xml.

    <dimen name="header_start_padding">16dp</dimen>
    <dimen name="header_end_padding">16dp</dimen>
    <dimen name="list_start_padding">10dp</dimen>
    <dimen name="list_end_padding">10dp</dimen>
    
Uso de values/dimens.xml

Figura 5. Uso de values/dimens.xml.

Teste diversos valores para ver qual funciona melhor.

Usar XML para compensar o queixo

Alguns smartwatches têm uma inserção (também conhecida como “queixo”) em uma tela circular. Se você não compensar, parte do seu design pode ficar encoberta por ela.

Por exemplo, você pode ter o seguinte design:

Design básico de coração

Figura 6. Design básico de coração.

O snippet activity_main.xml a seguir define o layout dele.

    <FrameLayout
      ...>
      <android.support.wear.widget.RoundedDrawable
        android:id="@+id/androidbtn"
        android:src="@drawable/ic_android"
        .../>
       <ImageButton
        android:id="@+id/lovebtn"
        android:src="@drawable/ic_favourite"
        android:paddingTop="5dp"
        android:paddingBottom="5dp"
        android:layout_gravity="bottom"
        .../>
    </FrameLayout>
    

Se você não fizer nada, parte do design desaparecerá no queixo.

Design básico de coração

Figura 7. Nenhuma correção aplicada.

Você pode usar o atributo fitsSystemWindows para configurar o preenchimento a fim de evitar o queixo. O snippet de activity_main.xml a seguir mostra o uso de fitsSystemWindows:

    <ImageButton
      android:id="@+id/lovebtn"
      android:src="@drawable/ic_favourite"
      android:paddingTop="5dp"
      android:paddingBottom="5dp"
      android:fitsSystemWindows="true"
      .../>
    
Uso de fitsSystemWindows

Figura 8. Uso do atributo fitsSystemWindows.

Os valores de preenchimento na parte superior e inferior que você definiu são modificados para que tudo caiba na janela do sistema. A maneira de corrigir isso é substituir os valores de preenchimento usando um InsetDrawable.

Crie um arquivo inset_favourite.xml para definir os valores de preenchimento:

    <inset
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:drawable="@drawable/ic_favourite"
      android:insetTop="5dp"
      android:insetBottom="5dp" />
    

Remova o preenchimento de activity_main.xml:

    <ImageButton
      android:id="@+id/lovebtn"
      android:src="@drawable/inset_favourite"
      android:paddingTop="5dp"
      android:paddingBottom="5dp"
      android:fitsSystemWindows="true"
      .../>
    
Uso de InsetDrawables

Figura 9. Uso de um InsetDrawables.

Gerenciar o queixo de modo programático

Se você precisar de mais controle do que é possível usando XML, poderá ajustar o layout de maneira programática. Para saber o tamanho do queixo, anexe um View.OnApplyWindowInsetsListener à visualização mais externa do seu layout.

Adicione o seguinte a MainActivity.java:

Kotlin

    private var chinSize: Int = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // find the outermost element
        findViewById<View>(R.id.outer_container).apply {
            // attach a View.OnApplyWindowInsetsListener
            setOnApplyWindowInsetsListener { v, insets ->
                chinSize = insets.systemWindowInsetBottom
                // The following line is important for inner elements which react to insets
                v.onApplyWindowInsets(insets)
                insets
            }
        }
    }
    

Java

    private int chinSize;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // find the outermost element
        final View container = findViewById(R.id.outer_container);
        // attach a View.OnApplyWindowInsetsListener
        container.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
            @Override
            public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
                chinSize = insets.getSystemWindowInsetBottom();
                // The following line is important for inner elements which react to insets
                v.onApplyWindowInsets(insets);
                return insets;
            }
        });
    }