Selecionar cores com a API Palette

Um bom design visual é essencial para um app de sucesso, e o esquema de cores é um componente principal do design. A biblioteca Palette é uma biblioteca do Jetpack que extrai cores em destaque de imagens para criar apps visualmente atraentes.

Você pode usar a biblioteca de paletas para criar temas de layout e aplicar cores personalizadas a elementos visuais do app. Por exemplo, você pode usar uma paleta para criar um cartão de título coordenado por cores para uma música com base na capa do álbum ou para ajustar a cor da barra de ferramentas de um app quando a imagem de plano de fundo mudar. O objeto Palette oferece acesso às cores em uma imagem Bitmap, além de fornecer seis perfis de cores principais do bitmap para informar suas escolhas de design.

Configurar a biblioteca

Para usar a biblioteca de paletas, adicione o seguinte ao build.gradle:

Kotlin

android {
    compileSdkVersion(33)
    ...
}

dependencies {
    ...
    implementation("androidx.palette:palette:1.0.0")
}

Groovy

android {
    compileSdkVersion 33
    ...
}

dependencies {
    ...
    implementation 'androidx.palette:palette:1.0.0'
}

Criar uma paleta

Um objeto Palette dá acesso às cores primárias de uma imagem, bem como às cores correspondentes para o texto sobreposto. Use paletas para projetar o estilo do app e mudar dinamicamente o esquema de cores do app com base em uma determinada imagem de origem.

Para criar uma paleta, primeiro instancie um Palette.Builder de um Bitmap. Você pode usar o Palette.Builder para personalizar a paleta antes de gerá-la. Esta seção descreve a geração e a personalização de paletas a partir de uma imagem de bitmap.

Gerar uma instância de Palette

Gere uma instância de Palette usando o método from(Bitmap bitmap) para criar um Palette.Builder usando um Bitmap.

O builder pode gerar a paleta de forma síncrona ou assíncrona. Use a geração síncrona de paleta se quiser criar a paleta na mesma linha de execução que o método que está sendo chamado. Se você gerar a paleta de forma assíncrona, em uma linha de execução diferente, use o método onGenerated() para acessar a paleta imediatamente após a criação dela.

O snippet de código abaixo fornece métodos de exemplo para os dois tipos de geração de paleta:

Kotlin

// Generate palette synchronously and return it.
fun createPaletteSync(bitmap: Bitmap): Palette = Palette.from(bitmap).generate()

// Generate palette asynchronously and use it on a different thread using onGenerated().
fun createPaletteAsync(bitmap: Bitmap) {
    Palette.from(bitmap).generate { palette ->
        // Use generated instance.
    }
}

Java

// Generate palette synchronously and return it.
public Palette createPaletteSync(Bitmap bitmap) {
  Palette p = Palette.from(bitmap).generate();
  return p;
}

// Generate palette asynchronously and use it on a different thread using onGenerated().
public void createPaletteAsync(Bitmap bitmap) {
  Palette.from(bitmap).generate(new PaletteAsyncListener() {
    public void onGenerated(Palette p) {
      // Use generated instance.
    }
  });
}

Se você precisar gerar paletas continuamente para uma lista classificada de imagens ou objetos, considere armazenar em cache as instâncias de Palette para evitar um desempenho lento da interface. Não crie as paletas na linha de execução principal.

Personalizar sua paleta

O Palette.Builder permite personalizar a paleta escolhendo quantas cores há na paleta resultante, qual área da imagem o builder usa para gerar a paleta e quais cores estão incluídas na paleta. Por exemplo, é possível filtrar a cor preta ou garantir que o builder use apenas a metade de cima de uma imagem para gerar sua paleta.

Ajuste o tamanho e as cores da paleta com os seguintes métodos da classe Palette.Builder:

addFilter()
Esse método adiciona um filtro que indica quais cores são permitidas na paleta resultante. Transmita seu próprio Palette.Filter e modifique o método isAllowed() para determinar quais cores serão filtradas da paleta.
maximumColorCount()
Este método configura o número máximo de cores na paleta. O valor padrão é 16 e o valor ideal depende da imagem de origem. Para paisagens, os valores ideais variam de 8 a 16, enquanto fotos com rostos geralmente têm valores de 24 a 32. O Palette.Builder leva mais tempo para gerar paletas com mais cores.
setRegion()
Esse método indica qual área do bitmap o builder usa ao criar a paleta. Você só pode usar esse método ao gerar a paleta usando um bitmap, e isso não afeta a imagem original.
addTarget()
Esse método permite que você faça sua própria correspondência de cores adicionando um perfil de cores Target ao builder. Se o Target padrão for insuficiente, os desenvolvedores avançados poderão criar o próprio Target usando um Target.Builder.

Extrair perfis de cores

Com base nos padrões do Material Design (link em inglês), a biblioteca Palette extrai os perfis de cores mais usados de uma imagem. Cada perfil é definido por um Target, e as cores extraídas da imagem de bitmap são pontuadas em cada perfil com base na saturação, luminância e preenchimento (número de pixels no bitmap representado pela cor). Para cada perfil, a cor com a melhor pontuação define o perfil de cores da imagem especificada.

Por padrão, um objeto Palette contém 16 cores primárias de uma determinada imagem. Ao gerar sua paleta, você pode personalizar o número de cores usando o Palette.Builder. A extração de mais cores oferece mais correspondências em potencial para cada perfil de cor, mas também faz com que Palette.Builder demora mais ao gerar a paleta.

A biblioteca de paletas tenta extrair os seis perfis de cores a seguir:

  • Light Vibrant
  • Vibrant
  • Dark Vibrant
  • Light Muted
  • silenciados;
  • Dark Muted

Cada um dos métodos get<Profile>Color() em Palette retorna a cor na paleta associada a esse perfil específico, em que <Profile> é substituído pelo nome de um dos seis perfis de cores. Por exemplo, o método para conseguir o perfil de cor "Dark Vibrant" é getDarkVibrantColor(). Como nem todas as imagens contêm todos os perfis de cores, forneça uma cor padrão para retornar.

A Figura 1 mostra uma foto e os perfis de cores correspondentes dos métodos get<Profile>Color().

Uma imagem que mostra um pôr do sol à esquerda e a paleta de cores extraída à direita.
Figura 1. Um exemplo de imagem e os perfis de cores extraídos, considerando a contagem máxima padrão de cores (16) para a paleta.

Usar amostras para criar esquemas de cores

A classe Palette também gera objetos Palette.Swatch para cada perfil de cor. Os objetos Palette.Swatch contêm a cor associada ao perfil, bem como o preenchimento da cor em pixels.

As amostras têm outros métodos para acessar mais informações sobre o perfil de cor, como valores de HSL e preenchimento de pixels. Você pode usar amostras para ajudar a criar esquemas de cores e temas de apps mais abrangentes usando os métodos getBodyTextColor() e getTitleTextColor(). Esses métodos retornam cores adequadas para uso sobre a cor da amostra.

Cada método get<Profile>Swatch() de Palette retorna a amostra associada a esse perfil específico, em que <Profile> é substituído pelo nome de um dos seis perfis de cores. Embora os métodos get<Profile>Swatch() da paleta não exijam parâmetros de valor padrão, eles retornam null se esse perfil específico não existir na imagem. Portanto, confira se uma amostra não é nula antes de usá-la. Por exemplo, o código abaixo extrai a cor do texto do título de uma paleta se a amostra "Vibrant" não for nula:

Kotlin

val vibrant = myPalette.vibrantSwatch
// In Kotlin, check for null before accessing properties on the vibrant swatch.
val titleColor = vibrant?.titleTextColor

Java

Palette.Swatch vibrant = myPalette.getVibrantSwatch();
if(vibrant != null){
    int titleColor = vibrant.getTitleTextColor();
    // ...
}

Para acessar todas as cores de uma paleta, o método getSwatches() retorna uma lista de todas as amostras geradas de uma imagem, incluindo os seis perfis de cores padrão.

O snippet de código a seguir usa os métodos dos snippets de código anteriores para gerar uma paleta de forma síncrona, acessar a amostra vibrante e mudar as cores de uma barra de ferramentas para corresponder à imagem de bitmap. A Figura 2 mostra a imagem resultante e a barra de ferramentas.

Kotlin

// Set the background and text colors of a toolbar given a bitmap image to
// match.
fun setToolbarColor(bitmap: Bitmap) {
    // Generate the palette and get the vibrant swatch.
    val vibrantSwatch = createPaletteSync(bitmap).vibrantSwatch

    // Set the toolbar background and text colors.
    // Fall back to default colors if the vibrant swatch isn't available.
    with(findViewById<Toolbar>(R.id.toolbar)) {
        setBackgroundColor(vibrantSwatch?.rgb ?:
                ContextCompat.getColor(context, R.color.default_title_background))
        setTitleTextColor(vibrantSwatch?.titleTextColor ?:
                ContextCompat.getColor(context, R.color.default_title_color))
    }
}

Java

// Set the background and text colors of a toolbar given a bitmap image to
// match.
public void setToolbarColor(Bitmap bitmap) {
    // Generate the palette and get the vibrant swatch.
    // See the createPaletteSync() method from the preceding code snippet.
    Palette p = createPaletteSync(bitmap);
    Palette.Swatch vibrantSwatch = p.getVibrantSwatch();

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

    // Load default colors.
    int backgroundColor = ContextCompat.getColor(getContext(),
        R.color.default_title_background);
    int textColor = ContextCompat.getColor(getContext(),
        R.color.default_title_color);

    // Check that the Vibrant swatch is available.
    if(vibrantSwatch != null){
        backgroundColor = vibrantSwatch.getRgb();
        textColor = vibrantSwatch.getTitleTextColor();
    }

    // Set the toolbar background and text colors.
    toolbar.setBackgroundColor(backgroundColor);
        toolbar.setTitleTextColor(textColor);
}
Uma imagem mostrando um pôr do sol e uma barra de ferramentas com TitleTextColor dentro
Figura 2. Exemplo de imagem com a barra de ferramentas de cores vibrantes e a cor do texto do título correspondente.