Como selecionar cores com a API Palette

Um bom design visual é essencial para um app ter sucesso, e os esquemas de cores são um componente principal do design. A biblioteca de paleta é uma biblioteca de suporte que extrai cores em destaque das imagens para ajudar a criar apps visualmente atraentes.

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

Configurar a biblioteca

Para usar a biblioteca de paleta, instale ou atualize a Biblioteca de Suporte do Android para a versão 24.0.0 ou versões posteriores e siga as instruções em Adicionar Biblioteca de Suporte para adicionar a biblioteca de paleta ao projeto de desenvolvimento do seu app.

Verifique se a versão especificada no identificador de dependência corresponde ao compileSdkVersion do app, definido no arquivo build.gradle:

    android {
      compileSdkVersion 28
      ...
    }

    dependencies {
      ...
      implementation 'com.android.support:palette-v7:28.0.0'
    }
    

Observação: se você está usando o plug-in do Android para Gradle 3.0.0 ou versões posteriores, use a palavra-chave "implementation". Se você tem outra versão do plug-in, use a palavra-chave "compile".

Para ver mais informações sobre como adicionar a dependência da paleta, leia sobre o recurso de suporte de paleta na documentação da biblioteca.

Criar uma paleta

Um objeto Palette oferece acesso às cores primárias de uma imagem, bem como às cores correspondentes para o texto sobreposto. Use as paletas para criar o estilo do seu app e alterar o esquema de cores do app de forma dinâmica com base em 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 como gerar e customizar uma paleta 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) de para criar um Palette.Builder a partir de um Bitmap. Em seguida, o builder poderá gerar a paleta de forma síncrona ou assíncrona.

Use a geração síncrona de paleta caso queira criar a paleta na mesma linha de execução do 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 ela ter sido criada.

O snippet de código a seguir mostra 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ê precisa 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 IU. Também não é recomendado criar paletas na sua linha de execução principal.

Personalizar sua paleta

O Palette.Builder permite que você personalize sua paleta escolhendo quantas cores haverá na paleta final, qual área da imagem o builder usará para gerar a paleta e quais cores serão permitidas. Por exemplo, é possível filtrar a cor preta ou garantir que o builder use somente a metade superior 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()
Este método adiciona um filtro que indica quais cores são permitidas na paleta final. Passe 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 imagens com rostos normalmente têm valores que ficam entre 24 e 32. O Palette.Builder demora mais para gerar paletas com mais cores.
setRegion()
Este método indica qual área do bitmap o builder usa ao criar a paleta. Você só pode usar esse método quando gerar a paleta a partir de um bitmap e isso não afetar a imagem original.
addTarget()
Este método permite que você faça sua própria correspondência de cores adicionando um perfil de cores Target ao builder. Se os Targets padrão não forem suficientes, desenvolvedores avançados poderão criar os próprios Targets usando um Target.Builder.

Extrair perfis de cores

Com base nos padrões do Material Design (link em inglês), a biblioteca de paleta 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 recebem uma pontuação em cada perfil com base na saturação, luminância e preenchimento (número de pixels no bitmap representados pela cor). Em cada perfil, a cor com a maior pontuação define o perfil de cores da imagem especificada.

Por padrão, um objeto Palette contém 16 cores primárias de determinada imagem. Ao gerar sua paleta, você poderá personalizar o número de cores dela usando o Palette.Builder. A extração de mais cores oferece mais correspondências possíveis para cada perfil de cores, mas também faz o Palette.Builder levar mais tempo para gerar a paleta.

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

  • Light Vibrant
  • Vibrant
  • Dark Vibrant
  • Light Muted
  • Muted
  • Dark Muted

Cada método get<Profile>Color() do Palette retorna a cor da 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 têm todos os perfis de cores, também é necessário fornecer uma cor padrão a ser retornada.

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

Figura 1. Exemplo de imagem e os perfis de cores extraídos, considerando a contagem de cores máxima padrão (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 a esse 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 por meio dos métodos getBodyTextColor() e getTitleTextColor(). Esses métodos retornam cores adequadas para usar sobre a cor da amostra.

Cada método get<Profile>Swatch() do 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, é necessário verificar se uma amostra não é nula antes de usá-la. Por exemplo, o código a seguir detecta 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 a partir de uma imagem, incluindo os seis perfis de cores padrão.

O snippet de código a seguir usa os métodos dos snippets acima para gerar uma paleta de forma síncrona, receber a amostra "Vibrant" dela e mudar as cores de uma barra de ferramentas para que correspondam à imagem de bitmap. A Figura 2 exibe a imagem e a barra de ferramentas resultantes.

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 is not 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 code snippet above
        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);
    }
    

Figura 2. Exemplo de imagem com barra de ferramentas de cores "Vibrant" e a cor do texto do título correspondente.