Temas do Material Design com o Jetpack Compose

1. Antes de começar

O Material Design é um sistema de design criado e aceito por designers e desenvolvedores do Google para criar experiências digitais de alta qualidade no Android e em outras plataformas da Web e de dispositivos móveis. Ele apresenta diretrizes sobre como criar a interface do app de uma forma legível, atraente e consistente.

Neste codelab, você vai aprender sobre os Temas do Material Design, que permitem usar esse sistema no seu app, com orientações sobre personalização de cores, tipografia e formas. É possível personalizar o quanto quiser. Você também vai aprender a adicionar uma barra de apps na parte de cima para mostrar o nome e o ícone do app.

Pré-requisitos

  • Familiaridade com a linguagem Kotlin, incluindo sintaxe, funções e variáveis.
  • Saber criar layouts no Compose, incluindo linhas e colunas com padding.
  • Saber criar listas simples no Compose.

O que você vai aprender

  • Como aplicar os temas do Material Design a um app do Compose.
  • Como adicionar uma paleta de cores personalizada ao app.
  • Como adicionar fontes personalizadas ao app.
  • Como adicionar formas personalizadas a elementos no app.
  • Como adicionar uma barra de apps à parte de cima do aplicativo.

O que você vai criar

  • Você vai criar um belo app que incorpora as práticas recomendadas do Material Design.

O que é necessário

  • Ter a versão mais recente do Android Studio.
  • Uma conexão de Internet para fazer o download do código inicial e das fontes.

2. Visão geral do app

Neste codelab, você vai criar o Woof, um app que mostra uma lista de cachorros e usa o Material Design para criar uma bela experiência.

92eca92f64b029cf.png

Neste codelab, vamos mostrar algumas das possibilidades usando temas do Material Design. Use este codelab para ter ideias sobre o uso dos temas do Material Design e melhorar a aparência dos apps que você criar.

Paleta de cores

Confira abaixo as paletas de cores para os temas claro e escuro que vamos criar.

Esta imagem tem o esquema de cores claras do app Woof.

Esta imagem tem o esquema de cores escuras para o app Woof.

Este é o app final nos temas claro e escuro.

Tema claro

Tema escuro

Tipografia

Confira abaixo os estilos de tipografia que você vai usar no app.

8ea685b3871d5ffc.png

Arquivo de tema

O arquivo Theme.kt contém todas as informações sobre o tema do app, definidas por cor, tipografia e forma. Esse é um arquivo importante que você precisa conhecer. Dentro dele está o WoofTheme() de composição, que define as cores, a tipografia e as formas do app.

@Composable
fun WoofTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColors
        else -> LightColors
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            setUpEdgeToEdge(view, darkTheme)
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        shapes = Shapes,
        typography = Typography,
        content = content
    )
}

/**
 * Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
 * light or dark depending on whether the [darkTheme] is enabled or not.
 */
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
    val window = (view.context as Activity).window
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.Transparent.toArgb()
    val navigationBarColor = when {
        Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
        Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
        // Min sdk version for this app is 24, this block is for SDK versions 24 and 25
        else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
    }
    window.navigationBarColor = navigationBarColor
    val controller = WindowCompat.getInsetsController(window, view)
    controller.isAppearanceLightStatusBars = !darkTheme
    controller.isAppearanceLightNavigationBars = !darkTheme
}

Em MainActivity.kt, o WoofTheme() é adicionado para fornecer os temas do Material Design para todo o app.

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           WoofTheme {
               Surface(
                   modifier = Modifier.fillMaxSize()
               ) {
                   WoofApp()
               }
           }
       }
   }
}

Dê uma olhada na WoofPreview(). O WoofTheme() foi adicionado para fornecer os temas do Material Design mostrados no WoofPreview().

@Preview
@Composable
fun WoofPreview() {
    WoofTheme(darkTheme = false) {
        WoofApp()
    }
}

3. Acessar o código inicial

Para começar, faça o download do código inicial:

Outra opção é clonar o repositório do GitHub:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git
$ cd basic-android-kotlin-compose-training-woof
$ git checkout starter

Procure o código no repositório do GitHub do Woof app (link em inglês).

Analisar o código inicial

  1. Abra o código inicial no Android Studio.
  2. Abra com.example.woof > data > Dog.kt. O arquivo contém a classe Dog data class que vai ser usada para representar a foto, o nome, a idade e os hobbies do cachorro. Ele também contém uma lista de cachorros e as informações que você vai usar como dados no app.
  3. Abra res > drawable. Ele contém todos os recursos de imagem necessários para este projeto, incluindo o ícone do app e os ícones e imagens de cachorros.
  4. Abra res > values > strings.xml. Ele contém as strings que você vai usar no app, incluindo o nome do aplicativo, os nomes dos cachorros, as descrições e muito mais.
  5. Abra MainActivity.kt. Ele contém o código para criar uma lista simples com a foto de um cachorro, o nome e a idade dele.
  6. WoofApp() contém uma LazyColumn que exibe os DogItems.
  7. DogItem() contém uma Row que mostra uma foto do cachorro e informações sobre ele.
  8. DogIcon() mostra uma foto do cachorro.
  9. DogInformation() mostra o nome e a idade do cachorro.
  10. WoofPreview() mostra uma prévia do app no painel Design.

Conferir se o emulador/dispositivo está no tema claro

Neste codelab, você vai trabalhar com os temas claro e escuro, mas a maior parte do guia foca no tema claro. Antes de começar, confira se o dispositivo/emulador está no tema claro.

Para conferir o app no tema claro, siga estas etapas no emulador ou dispositivo físico:

  1. Acesse o app Configurações.
  2. Pesquise tema escuro e clique nessa opção.
  3. Desative o tema escuro se ele estiver ativado.

Execute o código inicial para conferir como as coisas estão no começo. O app é uma lista que mostra cachorros, com fotos, nomes e idades. Ele funciona, mas não tem uma aparência muito boa. Vamos cuidar disso.

6d253ae50c63014d.png

4. Adicionar cores

A primeira coisa que você vai modificar no app Woof é o esquema de cores.

Um esquema de cores é a combinação de cores que o app usa. Combinações diferentes evocam sensações diferentes, o que influencia a reação das pessoas ao usar o app.

No sistema Android, a cor é representada por um valor hexadecimal (hex). Um código de cor hexadecimal começa com uma cerquilha (#) e é seguido por seis letras e/ou números que representam os componentes vermelho, verde e azul (RGB) dessa cor. As duas primeiras letras/números se referem ao vermelho, as duas seguintes ao verde e as duas últimas ao azul.

Esta imagem mostra os números hexadecimais usados para criar cores.

Uma cor também pode incluir um valor alfa (letras e/ou números) representando a transparência: #00 indica 0% de opacidade, ou seja, totalmente transparente, e #FF indica 100% de opacidade, ou seja, totalmente opaco. Quando incluído, o valor alfa é composto pelos primeiros dois caracteres do código de cor hexadecimal após o caractere cerquilha (#). Se não houver um valor alfa, ele vai ser considerado #FF, que indica 100% de opacidade (totalmente opaco).

Confira abaixo alguns exemplos de cores e seus valores hexadecimais.

2753d8cdd396c449.png

Usar o Material Theme Builder para criar um esquema de cores

Para criar um esquema de cores personalizado para o nosso app, vamos usar o Material Theme Builder.

  1. Clique neste link para acessar o Material Theme Builder (link em inglês).
  2. As cores primárias estão no painel esquerdo. Clique em "Primary":

Confira as quatro cores primárias no Material Theme Builder

  1. O seletor de cores do HCT será aberto.

Este é o seletor de cores do HCT para escolher uma cor personalizada no Material Theme Builder.

  1. Para criar o esquema de cores mostrado nas capturas de tela do app, mude a cor principal no seletor de cores. Na caixa de texto, substitua o texto atual por #006C4C. Assim, a cor principal do app vai ficar verde.

Isso mostra o seletor de cores HCT definido como verde

Observe que isso atualiza os apps na tela adotando um esquema de cores verde.

Isso mostra os apps do Material Theme Builder que reagem à mudança de cor do seletor de cores do HCT.

  1. Role a página para baixo para conferir o esquema completo de cores para os temas claro e escuro gerados a partir da cor inserida.

Esquema claro do Material Theme Builder

Esquema escuro gerado pelo Material Theme Builder

Você pode se perguntar quais são essas funções e como elas são utilizadas. Confira algumas das principais:

  • As cores primárias são usadas para os componentes mais importantes da interface.
  • As cores secundárias são usadas para componentes menos proeminentes na interface.
  • As cores terciárias são usadas para dar destaque a contrastes que podem ser usados para equilibrar cores primárias e secundárias ou chamar a atenção para um elemento, como um campo de entrada.
  • Os elementos de cor on aparecem sobre as outras cores da paleta e são aplicados principalmente a textos, iconografia e traços. Temos também uma cor onSurface, que aparece por cima da cor de superfície, e uma cor onPrimary, que aparece por cima da cor principal.

Esses slots oferecem um sistema de design coeso em que os componentes relacionados são coloridos de forma semelhante.

Mas chega de falar de teoria. Hora de adicionar essa bela paleta de cores ao app.

Adicionar a paleta de cores ao tema

Na página do Material Theme Builder, há a opção de clicar no botão Export para fazer o download de um arquivo Color.kt e Theme.kt com o tema personalizado que você criou.

Isso vai funcionar para adicionar o tema personalizado que criamos ao seu app. No entanto, como o arquivo Theme.kt gerado não inclui o código de cor dinâmica que vamos abordar mais adiante no codelab, copie os arquivos.

  1. Abra o arquivo Color.kt e substitua o conteúdo pelo código abaixo para copiar no novo esquema de cores.
package com.example.woof.ui.theme

import androidx.compose.ui.graphics.Color

val md_theme_light_primary = Color(0xFF006C4C)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFF89F8C7)
val md_theme_light_onPrimaryContainer = Color(0xFF002114)
val md_theme_light_secondary = Color(0xFF4D6357)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFCFE9D9)
val md_theme_light_onSecondaryContainer = Color(0xFF092016)
val md_theme_light_tertiary = Color(0xFF3D6373)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFC1E8FB)
val md_theme_light_onTertiaryContainer = Color(0xFF001F29)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFBFDF9)
val md_theme_light_onBackground = Color(0xFF191C1A)
val md_theme_light_surface = Color(0xFFFBFDF9)
val md_theme_light_onSurface = Color(0xFF191C1A)
val md_theme_light_surfaceVariant = Color(0xFFDBE5DD)
val md_theme_light_onSurfaceVariant = Color(0xFF404943)
val md_theme_light_outline = Color(0xFF707973)
val md_theme_light_inverseOnSurface = Color(0xFFEFF1ED)
val md_theme_light_inverseSurface = Color(0xFF2E312F)
val md_theme_light_inversePrimary = Color(0xFF6CDBAC)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF006C4C)
val md_theme_light_outlineVariant = Color(0xFFBFC9C2)
val md_theme_light_scrim = Color(0xFF000000)

val md_theme_dark_primary = Color(0xFF6CDBAC)
val md_theme_dark_onPrimary = Color(0xFF003826)
val md_theme_dark_primaryContainer = Color(0xFF005138)
val md_theme_dark_onPrimaryContainer = Color(0xFF89F8C7)
val md_theme_dark_secondary = Color(0xFFB3CCBE)
val md_theme_dark_onSecondary = Color(0xFF1F352A)
val md_theme_dark_secondaryContainer = Color(0xFF354B40)
val md_theme_dark_onSecondaryContainer = Color(0xFFCFE9D9)
val md_theme_dark_tertiary = Color(0xFFA5CCDF)
val md_theme_dark_onTertiary = Color(0xFF073543)
val md_theme_dark_tertiaryContainer = Color(0xFF244C5B)
val md_theme_dark_onTertiaryContainer = Color(0xFFC1E8FB)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF191C1A)
val md_theme_dark_onBackground = Color(0xFFE1E3DF)
val md_theme_dark_surface = Color(0xFF191C1A)
val md_theme_dark_onSurface = Color(0xFFE1E3DF)
val md_theme_dark_surfaceVariant = Color(0xFF404943)
val md_theme_dark_onSurfaceVariant = Color(0xFFBFC9C2)
val md_theme_dark_outline = Color(0xFF8A938C)
val md_theme_dark_inverseOnSurface = Color(0xFF191C1A)
val md_theme_dark_inverseSurface = Color(0xFFE1E3DF)
val md_theme_dark_inversePrimary = Color(0xFF006C4C)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFF6CDBAC)
val md_theme_dark_outlineVariant = Color(0xFF404943)
val md_theme_dark_scrim = Color(0xFF000000)
  1. Abra o arquivo Theme.kt e substitua o conteúdo pelo código abaixo para adicionar as novas cores ao tema.
package com.example.woof.ui.theme

import android.app.Activity
import android.os.Build
import android.view.View
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat

private val LightColors = lightColorScheme(
    primary = md_theme_light_primary,
    onPrimary = md_theme_light_onPrimary,
    primaryContainer = md_theme_light_primaryContainer,
    onPrimaryContainer = md_theme_light_onPrimaryContainer,
    secondary = md_theme_light_secondary,
    onSecondary = md_theme_light_onSecondary,
    secondaryContainer = md_theme_light_secondaryContainer,
    onSecondaryContainer = md_theme_light_onSecondaryContainer,
    tertiary = md_theme_light_tertiary,
    onTertiary = md_theme_light_onTertiary,
    tertiaryContainer = md_theme_light_tertiaryContainer,
    onTertiaryContainer = md_theme_light_onTertiaryContainer,
    error = md_theme_light_error,
    errorContainer = md_theme_light_errorContainer,
    onError = md_theme_light_onError,
    onErrorContainer = md_theme_light_onErrorContainer,
    background = md_theme_light_background,
    onBackground = md_theme_light_onBackground,
    surface = md_theme_light_surface,
    onSurface = md_theme_light_onSurface,
    surfaceVariant = md_theme_light_surfaceVariant,
    onSurfaceVariant = md_theme_light_onSurfaceVariant,
    outline = md_theme_light_outline,
    inverseOnSurface = md_theme_light_inverseOnSurface,
    inverseSurface = md_theme_light_inverseSurface,
    inversePrimary = md_theme_light_inversePrimary,
    surfaceTint = md_theme_light_surfaceTint,
    outlineVariant = md_theme_light_outlineVariant,
    scrim = md_theme_light_scrim,
)

private val DarkColors = darkColorScheme(
    primary = md_theme_dark_primary,
    onPrimary = md_theme_dark_onPrimary,
    primaryContainer = md_theme_dark_primaryContainer,
    onPrimaryContainer = md_theme_dark_onPrimaryContainer,
    secondary = md_theme_dark_secondary,
    onSecondary = md_theme_dark_onSecondary,
    secondaryContainer = md_theme_dark_secondaryContainer,
    onSecondaryContainer = md_theme_dark_onSecondaryContainer,
    tertiary = md_theme_dark_tertiary,
    onTertiary = md_theme_dark_onTertiary,
    tertiaryContainer = md_theme_dark_tertiaryContainer,
    onTertiaryContainer = md_theme_dark_onTertiaryContainer,
    error = md_theme_dark_error,
    errorContainer = md_theme_dark_errorContainer,
    onError = md_theme_dark_onError,
    onErrorContainer = md_theme_dark_onErrorContainer,
    background = md_theme_dark_background,
    onBackground = md_theme_dark_onBackground,
    surface = md_theme_dark_surface,
    onSurface = md_theme_dark_onSurface,
    surfaceVariant = md_theme_dark_surfaceVariant,
    onSurfaceVariant = md_theme_dark_onSurfaceVariant,
    outline = md_theme_dark_outline,
    inverseOnSurface = md_theme_dark_inverseOnSurface,
    inverseSurface = md_theme_dark_inverseSurface,
    inversePrimary = md_theme_dark_inversePrimary,
    surfaceTint = md_theme_dark_surfaceTint,
    outlineVariant = md_theme_dark_outlineVariant,
    scrim = md_theme_dark_scrim,
)

@Composable
fun WoofTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColors
        else -> LightColors
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            setUpEdgeToEdge(view, darkTheme)
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        shapes = Shapes,
        typography = Typography,
        content = content
    )
}

/**
 * Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
 * light or dark depending on whether the [darkTheme] is enabled or not.
 */
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
    val window = (view.context as Activity).window
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.Transparent.toArgb()
    val navigationBarColor = when {
        Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
        Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
        // Min sdk version for this app is 24, this block is for SDK versions 24 and 25
        else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
    }
    window.navigationBarColor = navigationBarColor
    val controller = WindowCompat.getInsetsController(window, view)
    controller.isAppearanceLightStatusBars = !darkTheme
    controller.isAppearanceLightNavigationBars = !darkTheme
}

Em WoofTheme(), o colorScheme val usa uma instrução when.

  • Se dynamicColor for verdadeiro e a versão do build for S ou mais recente, ela vai verificar se o dispositivo está em darkTheme ou não.
  • Se ele estiver no tema escuro, o colorScheme será definido como dynamicDarkColorScheme.
  • Se ele não estiver no tema escuro, será definido como dynamicLightColorScheme.
  • Se o app não estiver usando dynamicColorScheme, ele vai verificar se seu app está em darkTheme. Nesse caso, colorScheme será definido como DarkColors.
  • Se nenhuma dessas opções for verdadeira, colorScheme será definido como LightColors.

O arquivo copiado em Theme.kt tem dynamicColor definido como falso e os dispositivos com os quais estamos trabalhando estão no modo claro. Portanto, colorScheme será definido como LightColors.

val colorScheme = when {
       dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
           val context = LocalContext.current
           if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
       }

       darkTheme -> DarkColors
       else -> LightColors
   }
  1. Execute o app novamente. Observe que a barra de apps mudou de cor automaticamente.

b48b3fa2ecec9b86.png

Mapeamento de cores

Os componentes do Material Design são mapeados automaticamente para os slots de cor. Outros componentes importantes da interface, como os botões de ação flutuantes, também são padronizados com a cor principal. Isso significa que você não precisa atribuir explicitamente uma cor a um componente. Ele será automaticamente mapeado para um slot quando você definir o tema de cores no app. Você pode substituir isso definindo explicitamente uma cor no código. Leia mais sobre as funções de cor neste link.

Nesta seção, vamos unir a Row que contém o DogIcon() e DogInformation() com um Card para diferenciar as cores dos itens da lista com o plano de fundo.

  1. Na função combinável DogItem(), envolva a Row() com um Card().
Card() {
   Row(
       modifier = modifier
           .fillMaxWidth()
           .padding(dimensionResource(id = R.dimen.padding_small))
   ) {
       DogIcon(dog.imageResourceId)
       DogInformation(dog.name, dog.age)
   }
}
  1. Como o Card agora é o primeiro elemento combinável filho em DogItem(), transmita o modificador de DogItem() para Card e atualize o modificador de Row para uma nova instância de Modifier.
Card(modifier = modifier) {
   Row(
       modifier = Modifier
           .fillMaxWidth()
           .padding(dimensionResource(id = R.dimen.padding_small))
   ) {
       DogIcon(dog.imageResourceId)
       DogInformation(dog.name, dog.age)
   }
}
  1. Dê uma olhada no arquivo WoofPreview(). A cor dos itens da lista mudou automaticamente devido aos elementos combináveis Card. As cores parecem ótimas, mas não há espaçamento entre os itens da lista.

6d49372a1ef49bc7.png

Arquivo dimens

Assim como você usa o arquivo strings.xml para armazenar as strings no seu app, também é uma prática recomendada usar um arquivo chamado dimens.xml para armazenar valores de dimensão. Isso é útil para não fixar valores no código e, se necessário, você pode mudá-los em um único local.

Acesse app > res > values > dimens.xml e observe o arquivo. Ele armazena valores de dimensão para padding_small, padding_medium e image_size. Essas dimensões serão usadas em todo o app.

<resources>
   <dimen name="padding_small">8dp</dimen>
   <dimen name="padding_medium">16dp</dimen>
   <dimen name="image_size">64dp</dimen>
</resources>

Para adicionar um valor a partir do arquivo dimens.xml, este é o formato correto:

Mostra como formatar corretamente a adição de valores do recurso de dimensão

Por exemplo, para adicionar padding_small, transmita dimensionResource(id = R.dimen.padding_small).

  1. Em WoofApp(), adicione um modifier com padding_small na chamada para DogItem().
@Composable
fun WoofApp() {
    Scaffold { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}

Agora há mais definição entre itens de lista em WoofPreview().

c54f870f121fe02.png

Tema escuro

No sistema Android, você tem a opção de colocar o dispositivo no tema escuro. Um tema escuro usa cores mais escuras e discretas e:

  • Pode reduzir significativamente o consumo de energia (dependendo da tecnologia da tela do dispositivo).
  • Melhora a visibilidade para usuários com problemas de visão e que tenham sensibilidade ao brilho da luz.
  • Facilita o uso do dispositivo em ambientes com pouca luz.

O app pode ativar o recurso Forçar modo escuro, que faz com que o sistema implemente um tema escuro para você. No entanto, os usuários vão ter uma experiência melhor se você implementar o tema escuro no app. Assim, você tem controle total sobre o tema do app.

Ao criar um tema escuro próprio, é importante lembrar que as cores dele precisam atender aos padrões de contraste de acessibilidade (link em inglês). Os temas escuros usam uma cor de superfície escura com tons de cores limitados.

Conferir o tema escuro na visualização

Você já adicionou as cores ao tema escuro na etapa anterior. Para conferir o tema escuro, adicione outro elemento combinável da prévia em MainActivity.kt. Dessa forma, ao mudar o layout da interface no seu código, você vai poder conferir a aparência do tema claro e do tema escuro simultaneamente.

  1. Em WoofPreview(), crie uma nova função com o nome WoofDarkThemePreview() e faça uma anotação com @Preview e @Composable.
@Preview
@Composable
fun WoofDarkThemePreview() {

}
  1. Em DarkThemePreview(), adicione o WoofTheme(). Se o método WoofTheme() não fosse adicionado, nenhum estilo que adicionamos apareceria no app. Defina o parâmetro darkTheme como true.
@Preview
@Composable
fun WoofDarkThemePreview() {
   WoofTheme(darkTheme = true) {

   }
}
  1. Chame WoofApp() em WoofTheme().
@Preview
@Composable
fun WoofDarkThemePreview() {
   WoofTheme(darkTheme = true) {
       WoofApp()
   }
}

Role para baixo no painel Design para conferir o app no tema escuro, incluindo o plano de fundo mais escuro do app/item da lista e o texto mais claro. Compare as diferenças entre os temas claro e escuro.

Tema escuro

Tema claro

Conferir o tema escuro no dispositivo ou emulador

Para visualizar o app no tema escuro no emulador ou dispositivo físico, siga estas etapas:

  1. Acesse o app Configurações.
  2. Pesquise tema escuro e clique nessa opção.
  3. Ative o Tema escuro.
  4. Abra o app Woof novamente com o tema escuro ativado.

bc31a94207265b08.png

Este codelab se concentra mais no tema claro. Portanto, antes de avançar, desative o tema escuro.

  1. Acesse o app Configurações.
  2. Selecione Tela.
  3. Desative o Tema escuro.

Compare a aparência do app quando começamos e a de agora. Os itens e texto da lista estão mais definidos, e o esquema de cores está mais bonito.

Sem cor

Com cor (tema claro)

Com cor (tema escuro)

Cores dinâmicas

O Material Design 3 é altamente focado na personalização do usuário. Um novo recurso é a cor dinâmica, que cria um tema para o app com base no plano de fundo do usuário. Dessa forma, se o usuário adora verde e tem um plano de fundo azul no smartphone, o app Woof também vai estar em azul para refletir isso. O tema dinâmico está disponível apenas em determinados dispositivos com o Android 12 ou versões mais recentes.

Um tema personalizado pode ser usado para apps com cores fortes de marca e que também precisa ser implementado em dispositivos que não oferecem suporte a temas dinâmicos, para que o app ainda tenha um tema.

  1. Para ativar a cor dinâmica, abra Theme.kt, acesse o elemento combinável WoofTheme() e defina o parâmetro dynamicColor como verdadeiro.
@Composable
fun WoofTheme(
   darkTheme: Boolean = isSystemInDarkTheme(),
   dynamicColor: Boolean = true,
   content: @Composable () -> Unit
)
  1. Para mudar o plano de fundo de um dispositivo ou emulador, acesse as Configurações e pesquise Plano de fundo.
  2. Mude o plano de fundo para uma cor ou conjunto de cores.
  3. Execute o app novamente para conferir o tema dinâmico (observe que o dispositivo ou emulador precisa ser o Android 12 ou uma versão mais recente). Fique à vontade para testar isso com planos de fundo diferentes.

710bd13f6b189dc5.png

  1. Este codelab se concentra em temas personalizados. Portanto, desative dynamicColor antes de continuar.
@Composable
fun WoofTheme(
   darkTheme: Boolean = isSystemInDarkTheme(),
   dynamicColor: Boolean = false,
   content: @Composable () -> Unit
)

5. Adicionar formas

No entanto, aplicar uma forma pode mudar muito a aparência de um elemento combinável. As formas podem ser usadas para chamar atenção, identificar os componentes, comunicar o estado e expressar a marca.

Muitas formas são definidas usando RoundedCornerShape, que descreve um retângulo com cantos arredondados. O número transmitido define o quão redondos os cantos vão ser. Se RoundedCornerShape(0.dp) for usado, o retângulo não vai ter cantos arredondados. Se RoundedCornerShape(50.dp) for usado, os cantos vão ser totalmente circulares.

0 dp

25 dp

50 dp

Item de lista do Woof com modelagem

Item de lista do Woof com modelagem

Item de lista do Woof com modelagem

Você também pode personalizar ainda mais as formas adicionando diferentes porcentagens de arredondamento em cada canto. É muito divertido brincar com as formas.

Canto superior esquerdo: 50 dp
Canto inferior esquerdo: 25 dp
Canto superior direito: 0 dp
Canto inferior direito: 15 dp

Canto superior esquerdo: 15 dp
Canto inferior esquerdo: 50 dp
Canto superior direito: 50 dp
Canto inferior direito: 15 dp

Canto superior esquerdo: 0 dp
Canto inferior esquerdo: 50 dp
Canto superior direito: 0 dp
Canto inferior direito: 50 dp

Item de lista do Woof com modelagem

Item de lista do Woof com modelagem

Item de lista do Woof com modelagem

O arquivo Shape.kt é usado para definir formas de componentes no Compose. Existem três tipos de componentes: pequeno, médio e grande. Nesta seção, você vai modificar o componente Card, que é definido por um tamanho medium. Os componentes são agrupados em categorias de formas (link em inglês) com base no tamanho.

Nesta seção, você vai mudar a forma da imagem do cachorro para um círculo e modificar a forma do item da lista.

Transformar a imagem do cachorro em um círculo

  1. Abra o arquivo Shape.kt e observe que o parâmetro pequeno está definido como RoundedCornerShape(50.dp). Ele será usado para moldar a imagem em um círculo.
val Shapes = Shapes(
   small = RoundedCornerShape(50.dp),
)
  1. Abra MainActivity.kt. Em DogIcon(), adicione um atributo clip ao modifier da Image. Isso vai cortar a imagem em uma forma específica. Transmita o MaterialTheme.shapes.small.
import androidx.compose.ui.draw.clip

@Composable
fun DogIcon(
   @DrawableRes dogIcon: Int,
   modifier: Modifier = Modifier
) {
   Image(
       modifier = modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small))
           .clip(MaterialTheme.shapes.small),

Ao observar a WoofPreview(), você vai perceber que os ícones dos cachorros agora são circulares. No entanto, algumas fotos estão cortadas nas laterais e não aparecem como círculos.

1d4d1e5eaaddf71e.png

  1. Para tornar todas as fotos circulares, adicione atributos ContentScale e Crop. A imagem será cortada para caber no espaço disponível. Observe que contentScale é um atributo da Image e não faz parte de modifier.
import androidx.compose.ui.layout.ContentScale

@Composable
fun DogIcon(
   @DrawableRes dogIcon: Int,
   modifier: Modifier = Modifier
) {
   Image(
       modifier = modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small))
           .clip(MaterialTheme.shapes.small),
       contentScale = ContentScale.Crop,

Este é o elemento combinável DogIcon() completo.

@Composable
fun DogIcon(
    @DrawableRes dogIcon: Int,
    modifier: Modifier = Modifier
) {
    Image(
        modifier = modifier
            .size(dimensionResource(R.dimen.image_size))
            .padding(dimensionResource(R.dimen.padding_small))
            .clip(MaterialTheme.shapes.small),
        contentScale = ContentScale.Crop,
        painter = painterResource(dogIcon),

        // Content Description is not needed here - image is decorative, and setting a null content
        // description allows accessibility services to skip this element during navigation.

        contentDescription = null
    )
}

Agora, em WoofPreview(), os ícones são circulares.

fc93106990f5e161.png

Adicionar uma forma ao item da lista

Nesta seção, você vai adicionar uma forma ao item da lista. O item da lista já está sendo exibido por um Card. Um Card é uma superfície que pode conter um único elemento combinável, além de opções para decoração. A decoração pode ser adicionada pela borda, forma e muito mais. Nesta seção, você vai usar o Card para adicionar uma forma ao item da lista.

Item de lista do Woof com dimensões de forma adicionadas

  1. Abra o arquivo Shape.kt. Um Card é um componente médio, então você adiciona o parâmetro médio do objeto Shapes. Para este app, os cantos superior direito e inferior esquerdo do item da lista, mas não os tornam totalmente circulares. Para fazer isso, transmita 16.dp ao atributo medium.
medium = RoundedCornerShape(bottomStart = 16.dp, topEnd = 16.dp)

Como um Card, por padrão, já usa a forma média, você não precisa fazer uma definição explícita. Confira a Prévia e o Card com a nova forma.

Prévia do Woof com cards de forma

Ao retornar ao arquivo Theme.kt no WoofTheme() e analisar o MaterialTheme(), você vai notar que o atributo shapes está definido como o val Shapes que você acabou de atualizar.

MaterialTheme(
   colors = colors,
   typography = Typography,
   shapes = Shapes,
   content = content
)

Confira abaixo os itens da lista lado a lado antes e depois da modelagem. Observe como ele ficou mais bonito.

Sem formas

Com formas

6. Adicionar tipografia

A escala de tipografia do Material Design

Uma escala de tipografia é uma seleção de estilos de fonte que podem ser usados em um app, garantindo um estilo flexível e consistente. A escala de tipografia do Material Design (link em inglês) inclui 15 estilos de fonte com suporte ao sistema de tipografia. A nomenclatura e o agrupamento foram simplificados para: display, headline, title, body e label, com tamanhos grandes, médios e pequenos para cada um. Você só precisa usar essas opções caso queira personalizar o app. Se você não souber o que definir para cada categoria da escala, há uma escala de tipografia padrão que pode ser usada.

999a161dcd9b0ec4.png

A escala de tipografia contém categorias reutilizáveis de texto, cada uma com uma intenção de aplicação e significado.

Tela

Como o maior texto na tela, os estilos de "display" são reservados para textos ou números curtos e importantes. Eles funcionam melhor em telas grandes.

Título

"Headlines" são mais adequadas para textos curtos e de alta ênfase em telas menores. Esses estilos podem ser bons para marcar trechos do texto ou regiões de conteúdo importantes.

Title

Os "titles" são menores do que os estilos de "headlines" e devem ser usados para textos de prioridade média que permaneçam relativamente curtos.

Body

Os estilos de "body" são usados para trechos mais longos de texto no seu app.

Label

"Labels" são estilos utilitários menores, usados para elementos como o texto dentro de componentes ou para textos muito pequenos no corpo do conteúdo, como legendas.

Fontes

A plataforma Android oferece várias fontes, mas você pode personalizar seu app com uma fonte não fornecida por padrão. Fontes personalizadas podem adicionar personalidade e ser usadas para representar sua marca.

Nesta seção, você vai adicionar fontes personalizadas conhecidas como Abril Fatface, Montserrat Bold e Montserrat Regular. Você vai usar os títulos displayLarge e displayMedium e o texto bodyLarge do sistema de tipografia do Material Design para adicionar ao texto no app.

Criar uma fonte no diretório de recursos do Android.

Antes de adicionar fontes ao app, você vai precisar adicionar um diretório de fontes.

  1. Na visualização de projeto do Android Studio, clique com o botão direito do mouse na pasta res.
  2. Selecione New > Android Resource Directory.

Esta imagem mostra a navegação da estrutura de arquivos do Android Resource Directory.

  1. Nomeie o diretório como font, defina o tipo de recurso como font e clique em OK.

Esta imagem mostra como adicionar um diretório de fontes usando o New Resource Directory.

  1. Abra o novo diretório de recursos de fontes localizado em res > font.

Fazer o download de fontes personalizadas

Como você está usando fontes que não são fornecidas pela Plataforma Android, vai ser necessário fazer o download de fontes personalizadas.

  1. Acesse https://fonts.google.com/.
  2. Pesquise Montserrat e clique em Download family.
  3. Descompacte o arquivo ZIP.
  4. Abra a pasta Montserrat que você transferiu por download. Na pasta static, localize Montserrat-Bold.ttf e Montserrat-Regular.ttf (ttf significa TrueType Font e é o formato dos arquivos de fontes). Selecione os dois arquivos e arraste para o diretório de recursos de fontes do projeto no Android Studio.

Esta imagem mostra o conteúdo da pasta static com as fontes Montserrat.

  1. Na pasta de fontes, renomeie Montserrat-Bold.ttf como montserrat_bold.ttf e Montserrat-Regular.ttf como montserrat_regular.ttf.
  2. Pesquise Abril Fatface e clique em Download family.
  3. Abra a pasta Abril_Fatface. Selecione AbrilFatface-Regular.ttf e arraste para o diretório de recursos de fontes.
  4. Na pasta de fontes, renomeie Abril_Fatface_Regular.ttf como abril_fatface_regular.ttf.

O diretório de recursos de fontes do projeto vai ficar assim com os três arquivos de fontes personalizadas:

Esta imagem mostra os arquivos sendo adicionados à pasta de fontes.

Inicializar fontes

  1. Na janela do projeto, abra ui.theme > Type.kt. Inicialize as fontes transferidas por download abaixo das instruções de importação e acima de val Typography. Primeiro, inicialize Abril Fatface, definindo a fonte como FontFamily e transmitindo Font com o arquivo de fonte abril_fatface_regular.
​​import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import com.example.woof.R

val AbrilFatface = FontFamily(
   Font(R.font.abril_fatface_regular)
)
  1. Inicialize Montserrat, abaixo de Abril Fatface, definindo a fonte como FontFamily e transmitindo Font com o arquivo de fonte montserrat_regular. Para montserrat_bold, inclua também FontWeight.Bold. Mesmo que você transmita a versão em negrito do arquivo de fonte, o Compose não vai saber que o arquivo está em negrito. Portanto, faça a vinculação explícita de FontWeight.Bold.
import androidx.compose.ui.text.font.FontWeight

val AbrilFatface = FontFamily(
   Font(R.font.abril_fatface_regular)
)

val Montserrat = FontFamily(
   Font(R.font.montserrat_regular),
   Font(R.font.montserrat_bold, FontWeight.Bold)
)

Em seguida, defina os diferentes tipos de título como as fontes que você acabou de adicionar. O objeto Typography tem parâmetros para 13 tipos de fontes diferentes discutidos acima. Defina quantos forem necessários. Neste app, vamos definir displayLarge, displayMedium e bodyLarge. Na próxima parte deste app, você vai usar o labelSmall, então ele será adicionado agora.

Confira abaixo uma tabela que mostra a fonte, a espessura e o tamanho de cada título que você está adicionando.

8ea685b3871d5ffc.png

  1. Defina o atributo displayLarge da mesma forma que TextStyle e preencha fontFamily, fontWeight e fontSize com as informações da tabela acima. Isso significa que todo o texto definido como displayLarge terá Abril Fatface como a fonte definida, com uma espessura de fonte normal e um fontSize de 36.sp.

Repita esse processo para displayMedium, labelSmall e bodyLarge.

import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.sp

val Typography = Typography(
   displayLarge = TextStyle(
       fontFamily = AbrilFatface,
       fontWeight = FontWeight.Normal,
       fontSize = 36.sp
   ),
   displayMedium = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Bold,
       fontSize = 20.sp
   ),
   labelSmall = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Bold,
       fontSize = 14.sp
   ),
   bodyLarge = TextStyle(
       fontFamily = Montserrat,
       fontWeight = FontWeight.Normal,
       fontSize = 14.sp
   )
)

Se você acessar o arquivo Theme.kt no WoofTheme() e analisar o MaterialTheme(), o parâmetro typography será igual ao Typography val que você acabou de atualizar.

MaterialTheme(
   colors = colors,
   typography = Typography,
   shapes = Shapes,
   content = content
)

Adicionar tipografia ao texto do app

Agora, você vai adicionar os tipos de título a cada instância de texto no app.

  1. Adicione displayMedium como o estilo do dogName, já que ele é uma informação curta e importante. Adicione bodyLarge como o estilo de dogAge, já que essa informação funciona bem com tamanhos de texto menores.
@Composable
fun DogInformation(
   @StringRes dogName: Int,
   dogAge: Int,
   modifier: Modifier = Modifier
) {
   Column(modifier = modifier) {
       Text(
           text = stringResource(dogName),
           style = MaterialTheme.typography.displayMedium,
           modifier = Modifier.padding(top = dimensionResource(id = R.dimen.padding_small))
       )
       Text(
           text = stringResource(R.string.years_old, dogAge),
           style = MaterialTheme.typography.bodyLarge
       )
   }
}
  1. Agora na WoofPreview(), o nome do cachorro mostra a fonte Montserrat em negrito em 20.sp, e a idade do cachorro mostra a fonte Montserrat normal em 14.sp.

Prévia do Woof com tipografia adicionada

Confira abaixo os itens da lista antes e depois de adicionar a tipografia. Observe a diferença entre as fontes do nome e da idade dos cachorros.

Sem tipografia

Com tipografia

7. Adicionar uma barra na parte de cima

Um Scaffold é um layout que fornece slots para vários componentes e elementos de tela, como Image, Row ou Column. Um Scaffold também fornece um slot para uma TopAppBar, que vamos usar nesta seção.

Uma TopAppBar pode ser usada para muitos objetivos, mas neste caso você vai fazer o branding e dar uma personalidade ao app. Há quatro tipos diferentes de TopAppBar: centralizado, pequeno, médio e grande. Neste codelab, você vai implementar uma barra de apps superior central. Você vai criar um elemento combinável semelhante à captura de tela abaixo na seção topBar de um Scaffold.

172417c7b64372f7.png

Para esse app, a barra de cima consiste em uma Row com um logotipo e o texto do título do app. O logotipo mostra uma pata em gradiente e o título do app.

736f411f5067e0b5.png

Adicionar imagem e texto à barra de cima

  1. Em MainActivity.kt, crie um elemento combinável chamado WoofTopAppBar() com um modifier opcional.
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {

}
  1. Scaffold oferece suporte ao parâmetro contentWindowInsets, que pode ajudar a especificar encartes para o conteúdo de scaffold. WindowInsets são as partes da tela em que o app pode cruzar com a interface do sistema. Elas são transmitidas para o slot de conteúdo usando os parâmetros PaddingValues. Clique neste link para mais informações.

O valor contentWindowInsets é transmitido para a LazyColumn como o contentPadding.

@Composable
fun WoofApp() {
    Scaffold { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}
  1. No Scaffold, adicione um atributo topBar e o defina como WoofTopAppBar().
Scaffold(
   topBar = {
       WoofTopAppBar()
   }
)

Confira abaixo a aparência do elemento combinável WoofApp():

@Composable
fun WoofApp() {
    Scaffold(
        topBar = {
            WoofTopAppBar()
        }
    ) { it ->
        LazyColumn(contentPadding = it) {
            items(dogs) {
                DogItem(
                    dog = it,
                    modifier = Modifier.padding(dimensionResource(R.dimen.padding_small))
                )
            }
        }
    }
}

Nada mudou em WoofPreview() porque não há nada na WoofTopAppBar(). Vamos mudar isso.

Prévia do Woof com tipografia

  1. Na WoofTopAppBar() Composable, adicione uma CenterAlignedTopAppBar() e defina o parâmetro do modificador para a WoofTopAppBar() transmitida.
import androidx.compose.material3.CenterAlignedTopAppBar

@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
   CenterAlignedTopAppBar(
       modifier = modifier
   )
}
  1. Para o parâmetro de título, transmita uma Row que vai conter a Image e o Text da CenterAlignedTopAppBar.
@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier){
   CenterAlignedTopAppBar(
       title = {
           Row() {

           }
       },
       modifier = modifier
   )
}
  1. Adicione o logotipo Image à Row.
  • Defina o tamanho da imagem no modifier como image_size no arquivo dimens.xml e o padding como padding_small no arquivo dimens.xml.
  • Use painter para definir a Image como ic_woof_logo a partir da pasta drawable.
  • Defina contentDescription como null. Neste caso, o logotipo do app não adiciona informações semânticas para usuários com problemas de visão. Portanto, não precisamos adicionar uma descrição de conteúdo.
Row() {
   Image(
       modifier = Modifier
           .size(dimensionResource(id = R.dimen.image_size))
           .padding(dimensionResource(id = R.dimen.padding_small)),
       painter = painterResource(R.drawable.ic_woof_logo),
       contentDescription = null
   )
}
  1. Em seguida, adicione um elemento combinável Text dentro da Row após a Image..
  • Use stringResource() para defini-lo como o valor de app_name. Isso define o texto como o nome do app, que é armazenado em strings.xml.
  • Defina o estilo do texto como displayLarge, já que o nome do app é curto e importante.
Text(
   text = stringResource(R.string.app_name),
   style = MaterialTheme.typography.displayLarge
)

Prévia do Woof com a barra de apps superior

É isso que aparece em WoofPreview(). Parece um pouco fora do padrão porque o ícone e o texto não estão alinhados verticalmente.

  1. Para corrigir isso, adicione um parâmetro de valor verticalAlignment ao Row e o defina como Alignment.CenterVertically.
import androidx.compose.ui.Alignment

Row(
   verticalAlignment = Alignment.CenterVertically
)

Prévia do Woof com a barra superior vertical centralizada no app

Parece muito melhor!

Este é o elemento combinável WoofTopAppBar() completo:

@Composable
fun WoofTopAppBar(modifier: Modifier = Modifier) {
   CenterAlignedTopAppBar(
       title = {
           Row(
               verticalAlignment = Alignment.CenterVertically
           ) {
               Image(
                   modifier = Modifier
                       .size(dimensionResource(id = R.dimen.image_size))
                       .padding(dimensionResource(id = R.dimen.padding_small)),
                   painter = painterResource(R.drawable.ic_woof_logo),

                   contentDescription = null
               )
               Text(
                   text = stringResource(R.string.app_name),
                   style = MaterialTheme.typography.displayLarge
               )
           }
       },
       modifier = modifier
   )
}

Execute o app e confira como a TopAppBar dá um toque final perfeito.

Sem a barra de apps na parte de cima

Com a barra de apps na parte de cima

Agora, confira o app final com o tema escuro.

2776e6a45cf3434a.png

Parabéns, você chegou ao fim do codelab.

8. Acessar o código da solução

Para baixar o código do codelab concluído, use estes comandos git:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof.git
$ cd basic-android-kotlin-compose-training-woof
$ git checkout material

Se preferir, você pode baixar o repositório como um arquivo ZIP, descompactar e abrir no Android Studio.

Se você quiser conferir o código da solução, acesse o GitHub (em inglês).

9. Conclusão

Você acabou de criar seu primeiro app do Material Design. Você criou uma paleta de cores personalizada para os temas claro e escuro, criou formas para diferentes componentes, fez o download de fontes e as adicionou ao app, além de ter criado uma ótima barra na parte de cima para finalizar o projeto. Aplique as habilidades aprendidas neste codelab e mude cores, formas e tipografias para deixar os apps do seu jeito.

Resumo

  • Com os Temas do Material Design (link em inglês), você pode usar o Material Design no seu app com orientações sobre personalização de cores, tipografia e formas.
  • O arquivo Theme.kt é onde o tema é definido por meio de um elemento combinável chamado [your app name]+Theme(), WoofTheme(), no caso do app. Nessa função, o objeto MaterialTheme define color, typography, shapes e content do app.
  • Color.kt é onde você lista as cores usadas no app. Em seguida, em Theme.kt, você atribui as cores em LightColorPalette e DarkColorPalette a slots específicos. Nem todos os slots precisam ser atribuídos.
  • O app pode ativar o recurso Forçar modo escuro, que faz com que o sistema implemente um tema escuro para você. No entanto, os usuários vão ter uma experiência melhor se você implementar o tema escuro no app. Assim, você tem controle total sobre o tema do app.
  • Shapes.kt é onde você define as formas do app. Existem três tamanhos de formas (pequeno, médio, grande) e você pode especificar como os cantos vão ser arredondados.
  • As formas podem ser usadas para chamar atenção, identificar os componentes, comunicar o estado e expressar a marca.
  • Type.kt é onde você inicializa as fontes e atribui fontFamily, fontWeight e fontSize para a escala de tipografia do Material Design.
  • A escala de tipografia do Material Design (link em inglês) inclui um intervalo de estilos contrastantes com suporte às necessidades e aos conteúdos do app. A escala de tipografia é uma combinação de 15 estilos com suporte ao sistema de tipografia.

10. Saiba mais