Visão geral dos drawables

Testar o Compose
O Jetpack Compose é o kit de ferramentas de interface recomendado para Android. Aprenda a mostrar gráficos no Compose.

Quando você precisa mostrar imagens estáticas no seu app, use a classe Drawable e as subclasses dela para desenhar formas e de imagens de contêiner. Um Drawable é uma abstração geral para algo que possa ser desenhado. As várias subclasses ajudam com funções específicas e você pode estendê-los para definir seus próprios objetos drawable que se comportam de maneiras únicas.

Há duas maneiras de definir e instanciar um Drawable, além de usar os construtores da classe:

  • Inflar um recurso de imagem (arquivo de bitmap) salvo no projeto.
  • Inflar um recurso XML que define as propriedades do drawable.

Observação: Você pode preferir usar um drawable vetorial, que define uma imagem com um conjunto de pontos, linhas e curvas, junto com as informações de cor associadas. Isso permite drawables vetoriais ser dimensionados para diferentes tamanhos sem perder a qualidade. Para mais informações, consulte Vector Visão geral dos drawables.

Criar drawables a partir de imagens de recursos

É possível adicionar gráficos ao seu app referenciando um arquivo de imagem do seu recursos do projeto. Os tipos de arquivo aceitos são PNG (preferencial), JPG (aceitável), e GIF (não recomendado). Ícones, logotipos e outros elementos gráficos do app, como os usados em jogos, são ideais para essa técnica.

Para usar um recurso de imagem, adicione o arquivo ao res/drawable/ do seu projeto. No projeto, faça referência à imagem recurso do seu código ou layout XML. De qualquer forma, ele é chamado de ID do recurso, que é o nome do arquivo sem a extensão do tipo de arquivo. Para por exemplo, consulte my_image.png como my_image.

Observação: recursos de imagem colocados na O diretório res/drawable/ pode ser otimizado automaticamente com compactação de imagem sem perdas pela ferramenta aapt durante o build de desenvolvimento de software. Por exemplo, um PNG de cores verdadeiras que não exige mais de 256 cores. podem ser convertidos para um PNG de 8 bits com uma paleta de cores. Isso resulta em uma imagem com a mesma qualidade, mas que requerem menos memória. Como resultado, os binários de imagem colocados nesse diretório podem mudar no tempo de build. Se você planeja ler um imagem como bitstream para convertê-la em um bitmap, coloque suas imagens no res/raw/, onde a ferramenta aapt não modificá-los.

O snippet de código abaixo demonstra como criar uma ImageView que usa uma imagem criada a partir de um recurso drawable e o adiciona ao layout:

Kotlin

private lateinit var constraintLayout: ConstraintLayout

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Instantiate an ImageView and define its properties
    val i = ImageView(this).apply {
        setImageResource(R.drawable.my_image)
        contentDescription = resources.getString(R.string.my_image_desc)

        // set the ImageView bounds to match the Drawable's dimensions
        adjustViewBounds = true
        layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT)
    }

    // Create a ConstraintLayout in which to add the ImageView
    constraintLayout = ConstraintLayout(this).apply {

        // Add the ImageView to the layout.
        addView(i)
    }

    // Set the layout as the content view.
    setContentView(constraintLayout)
}

Java

ConstraintLayout constraintLayout;

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // Create a ConstraintLayout in which to add the ImageView
  constraintLayout = new ConstraintLayout(this);

  // Instantiate an ImageView and define its properties
  ImageView i = new ImageView(this);
  i.setImageResource(R.drawable.my_image);
  i.setContentDescription(getResources().getString(R.string.my_image_desc));

  // set the ImageView bounds to match the Drawable's dimensions
  i.setAdjustViewBounds(true);
  i.setLayoutParams(new ViewGroup.LayoutParams(
          ViewGroup.LayoutParams.WRAP_CONTENT,
          ViewGroup.LayoutParams.WRAP_CONTENT));

  // Add the ImageView to the layout and set the layout as the content view.
  constraintLayout.addView(i);
  setContentView(constraintLayout);
}

Em outros casos, processe seu recurso de imagem como um objeto Drawable, conforme mostrado abaixo. exemplo:

Kotlin

val myImage: Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)

Java

Resources res = context.getResources();
Drawable myImage = ResourcesCompat.getDrawable(res, R.drawable.my_image, null);

Aviso:cada recurso exclusivo do seu projeto pode manter apenas um estado, não importa quantos objetos diferentes você instanciar para ele. Por exemplo, se você instanciar dois objetos Drawable do mesmo recurso de imagem e alterar uma propriedade (como o alfa) de um objeto, isso também afetará com o outro. Ao lidar com várias instâncias de um recurso de imagem, em vez de transformar diretamente o objeto Drawable, execute uma pré-adolescente animação.

O snippet de XML abaixo mostra como adicionar um recurso drawable a um ImageView no layout XML:

<ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/my_image"
        android:contentDescription="@string/my_image_desc" />

Para mais informações sobre o uso de recursos do projeto, consulte Recursos.

Observação:ao usar recursos de imagem como a origem dos drawables, Certifique-se de que as imagens tenham o tamanho apropriado para várias densidades de pixel. Se o estiverem incorretas, elas serão dimensionadas para caber, o que pode causar artefatos nos seus drawables. Para mais informações, consulte Suporte a diferentes densidades de pixel

Criar drawables a partir de recursos XML

Se houver um Drawable que você gostaria de criar, que não depende inicialmente de variáveis definidas pelo seu ou interação do usuário, definir Drawable em XML é uma boa opção. Uniforme se você espera que o Drawable mude as propriedades durante a interação do usuário. com seu aplicativo, considere definir o objeto em XML, já que é possível modificar as propriedades depois o objeto foi instanciado.

Depois de definir o Drawable em XML, salve o arquivo na res/drawable/ do seu projeto. O exemplo a seguir mostra o XML que define um TransitionDrawable recurso herdado de Drawable:

<!-- res/drawable/expand_collapse.xml -->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/image_expand"/>
    <item android:drawable="@drawable/image_collapse"/>
</transition>

Em seguida, recupere e instancie o objeto chamando Resources#getDrawable() e passando o ID do recurso do seu arquivo XML. Qualquer um Subclasse Drawable com suporte ao método inflate() pode ser definido em XML e instanciado pelo seu app.

Cada classe de drawable que oferece suporte à inflação de XML utiliza atributos XML específicos que ajudam a definir as propriedades do objeto. O código a seguir instancia TransitionDrawable e o define como o conteúdo de um Objeto ImageView:

Kotlin

val transition= ResourcesCompat.getDrawable(
        context.resources,
        R.drawable.expand_collapse,
        null
) as TransitionDrawable

val image: ImageView = findViewById(R.id.toggle_image)
image.setImageDrawable(transition)

// Description of the initial state that the drawable represents.
image.contentDescription = resources.getString(R.string.collapsed)

// Then you can call the TransitionDrawable object's methods.
transition.startTransition(1000)

// After the transition is complete, change the image's content description
// to reflect the new state.

Java

Resources res = context.getResources();
TransitionDrawable transition =
    (TransitionDrawable) ResourcesCompat.getDrawable(res, R.drawable.expand_collapse, null);

ImageView image = (ImageView) findViewById(R.id.toggle_image);
image.setImageDrawable(transition);

// Description of the initial state that the drawable represents.
image.setContentDescription(getResources().getString(R.string.collapsed));

// Then you can call the TransitionDrawable object's methods.
transition.startTransition(1000);

// After the transition is complete, change the image's content description
// to reflect the new state.

Para mais informações sobre os atributos XML compatíveis, consulte as classes listados acima.

Drawables de formato

Um objeto ShapeDrawable pode ser uma boa opção quando você quer desenhar dinamicamente um gráfico bidimensional. Você pode desenhar formas primitivas de forma programática em um objeto ShapeDrawable; e aplicar os estilos que o app precisa.

ShapeDrawable é uma subclasse de Drawable. Por isso, você pode usar uma ShapeDrawable em que um Drawable é esperado. Para Por exemplo, é possível usar um objeto ShapeDrawable para definir o plano de fundo de uma visualização transmitindo-a para o método setBackgroundDrawable() dela. Você também pode desenhar sua forma visualização personalizada e adicioná-la a um layout no seu app.

Como ShapeDrawable tem o próprio método draw(), é possível criar um subclasse de View que desenha a ShapeDrawable objeto durante o evento onDraw(), conforme mostrado no este exemplo de código:

Kotlin

class CustomDrawableView(context: Context) : View(context) {
    private val drawable: ShapeDrawable = run {
        val x = 10
        val y = 10
        val width = 300
        val height = 50
        contentDescription = context.resources.getString(R.string.my_view_desc)

        ShapeDrawable(OvalShape()).apply {
            // If the color isn't set, the shape uses black as the default.
            paint.color = 0xff74AC23.toInt()
            // If the bounds aren't set, the shape can't be drawn.
            setBounds(x, y, x + width, y + height)
        }
    }

    override fun onDraw(canvas: Canvas) {
        drawable.draw(canvas)
    }
}

Java

public class CustomDrawableView extends View {
  private ShapeDrawable drawable;

  public CustomDrawableView(Context context) {
    super(context);

    int x = 10;
    int y = 10;
    int width = 300;
    int height = 50;
    setContentDescription(context.getResources().getString(
            R.string.my_view_desc));

    drawable = new ShapeDrawable(new OvalShape());
    // If the color isn't set, the shape uses black as the default.
    drawable.getPaint().setColor(0xff74AC23);
    // If the bounds aren't set, the shape can't be drawn.
    drawable.setBounds(x, y, x + width, y + height);
  }

  protected void onDraw(Canvas canvas) {
    drawable.draw(canvas);
  }
}

Use a classe CustomDrawableView no exemplo de código acima, como você usaria qualquer outra visualização personalizada. Por exemplo, é possível adicioná-lo de forma programática a uma atividade no app, como mostrado abaixo exemplo:

Kotlin

private lateinit var customDrawableView: CustomDrawableView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    customDrawableView = CustomDrawableView(this)

    setContentView(customDrawableView)
}

Java

CustomDrawableView customDrawableView;

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  customDrawableView = new CustomDrawableView(this);

  setContentView(customDrawableView);
}

Se você preferir usar a visualização personalizada no layout XML, o A classe CustomDrawableView precisa substituir o construtor View(Context, AttributeSet), que é chamado quando a classe é inflada a partir de XML. O exemplo a seguir mostra como declarar CustomDrawableView no layout XML:

<com.example.shapedrawable.CustomDrawableView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />

A classe ShapeDrawable, assim como muitas outras de drawable no pacote android.graphics.drawable, permite definir várias propriedades do objeto usando métodos públicos. Alguns exemplos propriedades que talvez você queira ajustar incluem transparência alfa, filtro de cor, pontilhamento, opacidade e cor.

Também é possível definir formas básicas de drawable por meio de recursos XML. Para mais informações, consulte Drawable de formato em Tipos de recursos drawable.

Drawables NinePatch

Um gráfico NinePatchDrawable é de bitmap esticável que pode ser usada como plano de fundo de uma visualização. Android redimensiona automaticamente o gráfico para acomodar o conteúdo da visualização. Um exemplo de uso de uma imagem NinePatch é o plano de fundo usado pelo sistema botões: os botões devem esticar para acomodar strings de vários comprimentos. Um O gráfico NinePatch é uma imagem PNG padrão que inclui uma borda extra de 1 pixel. Ele precisa ser salvo com a extensão 9.png no res/drawable/ do seu projeto.

Use a borda para definir as áreas esticáveis e estáticas da imagem. Você indica uma seção esticável desenhando uma ou mais imagens com 1 pixel de largura linha(s) preta(s) na parte esquerda e superior da borda (os outros pixels da borda deve ser totalmente transparente ou branco). É possível ter quantas seções esticáveis como quiser. O tamanho relativo das seções esticáveis permanece o mesmo, então a maior seção é sempre a maior.

Também é possível definir uma seção de drawable opcional da imagem (efetivamente, as linhas de preenchimento) desenhando uma linha à direita e outra na parte inferior. Se um O objeto View define o gráfico NinePatch como segundo plano. e, em seguida, especifica o texto da visualização, ele se estica para que todo o texto ocupa somente a área designada pelas linhas à direita e inferior (se incluídas). Se as linhas de padding não estiverem incluídas, o Android usará as linhas esquerda e superior para definem a área do desenhável.

Para esclarecer a diferença entre as linhas, as linhas esquerda e superior definem quais pixels da imagem podem ser replicados a fim de esticar a imagem. As linhas inferior e direita definem a área relativa dentro da imagem que que o conteúdo da visualização possa ocupar.

A Figura 1 mostra um exemplo de gráfico NinePatch usado para definir um botão:

Imagem de área elástica
e caixa de padding

Figura 1:exemplo de um gráfico NinePatch que define um botão

Este gráfico NinePatch define uma área esticável com as partes esquerda e superior e a área do drawable com as linhas inferior e direita. Na imagem de cima, as linhas cinza pontilhadas identificam as regiões da imagem que são replicadas para esticar a imagem. O retângulo rosa na imagem de baixo identifica a região em que o conteúdo da visualização é permitido. Se o conteúdo não cabem nessa região, a imagem é esticada para ajustá-las.

A ferramenta Draw 9-patch oferece uma É uma forma muito prática de criar suas imagens NinePatch usando gráficos WYSIWYG. editor. Avisos serão gerados até mesmo se a região que você definiu para o área corre o risco de produzir artefatos de desenho como resultado da aplicação de forma consistente.

O XML de layout de exemplo a seguir demonstra como adicionar um gráfico NinePatch alguns botões. A imagem NinePatch é salva res/drawable/my_button_background.9.png:

<Button android:id="@+id/tiny"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerInParent="true"
        android:text="Tiny"
        android:textSize="8sp"
        android:background="@drawable/my_button_background"/>

<Button android:id="@+id/big"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:text="Biiiiiiig text!"
        android:textSize="30sp"
        android:background="@drawable/my_button_background"/>

layout_width e layout_height atributos sejam definidos como wrap_content para que o botão se encaixe perfeitamente. ao redor do texto.

A Figura 2 mostra os dois botões renderizados da imagem XML e NinePatch como mostrado acima. Observe como a largura e a altura do botão variam de acordo com o texto, e a imagem de plano de fundo se estica para acomodá-la.

Imagem de imagens pequenas e
botões de tamanho normal

Figura 2. Botões renderizados usando um XML e um gráfico NinePatch

Drawables personalizados

Quando você quiser criar alguns desenhos personalizados, estenda a classe Drawable (ou qualquer uma das subclasses relacionadas).

O método mais importante a ser implementado é draw(Canvas) porque isso fornece o objeto Canvas que você precisa usar para fornecer suas instruções de desenho.

O código a seguir mostra uma subclasse simples de Drawable. que desenha um círculo:

Kotlin

class MyDrawable : Drawable() {
    private val redPaint: Paint = Paint().apply { setARGB(255, 255, 0, 0) }

    override fun draw(canvas: Canvas) {
        // Get the drawable's bounds
        val width: Int = bounds.width()
        val height: Int = bounds.height()
        val radius: Float = Math.min(width, height).toFloat() / 2f

        // Draw a red circle in the center
        canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, redPaint)
    }

    override fun setAlpha(alpha: Int) {
        // This method is required
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        // This method is required
    }

    override fun getOpacity(): Int =
        // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE
        PixelFormat.OPAQUE
}

Java

public class MyDrawable extends Drawable {
    private final Paint redPaint;

    public MyDrawable() {
        // Set up color and text size
        redPaint = new Paint();
        redPaint.setARGB(255, 255, 0, 0);
    }

    @Override
    public void draw(Canvas canvas) {
        // Get the drawable's bounds
        int width = getBounds().width();
        int height = getBounds().height();
        float radius = Math.min(width, height) / 2;

        // Draw a red circle in the center
        canvas.drawCircle(width/2, height/2, radius, redPaint);
    }

    @Override
    public void setAlpha(int alpha) {
        // This method is required
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        // This method is required
    }

    @Override
    public int getOpacity() {
        // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE
        return PixelFormat.OPAQUE;
    }
}

Depois, é possível adicionar o desenhável onde quiser, como em uma ImageView, como mostrado aqui:

Kotlin

val myDrawing = MyDrawable()
val image: ImageView = findViewById(R.id.imageView)
image.setImageDrawable(myDrawing)
image.contentDescription = resources.getString(R.string.my_image_desc)

Java

MyDrawable mydrawing = new MyDrawable();
ImageView image = findViewById(R.id.imageView);
image.setImageDrawable(mydrawing);
image.setContentDescription(getResources().getString(R.string.my_image_desc));

No Android 7.0 (nível 24 da API) e versões mais recentes, também é possível definir instâncias do com XML das seguintes maneiras:

  • Use o nome de classe totalmente qualificado como o nome do elemento XML. Para essa abordagem, o modelo A classe drawable precisa ser pública de nível superior:
    <com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="#ffff0000" />
    
  • Usar drawable como o nome da tag XML e especificar a classe totalmente qualificada name do atributo de classe. Essa abordagem pode ser usada para classes públicas de nível superior e classes internas estáticas públicas:
    <drawable xmlns:android="http://schemas.android.com/apk/res/android"
        class="com.myapp.MyTopLevelClass$MyDrawable"
        android:color="#ffff0000" />
    
.

Adicionar tonalidade a drawables

Com o Android 5.0 (API de nível 21) e posteriores, é possível colorir bitmaps e 9-patches definidos como máscaras alfa. É possível colori-los com recursos de cor ou atributos de tema que determinam a cor recursos, como ?android:attr/colorPrimary. Normalmente, você cria esses recursos apenas uma vez e colore-as automaticamente para combinar com seu tema.

Você pode aplicar uma tonalidade a BitmapDrawable, NinePatchDrawable ou VectorDrawable com o método setTint(). Você pode definir a cor e o modo da tonalidade nos seus layouts com android:tint e android:tintMode.

Extrair cores em destaque de uma imagem

A Biblioteca de Suporte do Android inclui a classe Palette, que permite extrair as cores em destaque de uma imagem. Carregue seus drawables como um Bitmap e transmita-o para Palette para acessar as cores dele. Para mais informações, leia Seleção de cores com a API Palette.