Quando você precisa exibir imagens estáticas no seu app, é possível usar a classe Drawable
e as subclasses relacionadas para desenhar formas e imagens. Um Drawable
é uma abstração geral para algo que pode ser desenhado. As diversas subclasses ajudam com cenários de imagem específicos, e é possível estendê-las para definir os 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: talvez você prefira usar um drawable vetorial, que define uma imagem com um conjunto de pontos, linhas e curvas, junto às informações de cor associadas. Isso permite que drawables vetoriais sejam dimensionados para tamanhos diferentes sem perda de qualidade. Para mais informações, consulte Visão geral de drawables vetoriais.
Criar drawables a partir de imagens de recursos
É possível adicionar gráficos ao app referenciando um arquivo de imagem dos recursos do projeto. Os tipos de arquivo compatíveis são PNG (preferencial), JPG (aceitável) e GIF (não recomendado). Ícones do app, logotipos e outros elementos gráficos, como aqueles usados em jogos, são adequados para essa técnica.
Para usar um recurso de imagem, adicione seu arquivo ao diretório res/drawable/
do projeto. Quando você estiver no projeto, poderá referenciar o recurso de imagem do seu código ou layout XML. De qualquer forma, ele é referenciado por meio de um código de recurso, que é o nome do arquivo sem a extensão de tipo. Por exemplo, consulte my_image.png
como my_image
.
Observação: recursos de imagem colocados no diretório res/drawable/
podem ser otimizados automaticamente com a compactação de imagem sem perdas pela ferramenta aapt
durante o processo de compilação. Por exemplo, um PNG de cor verdadeira que não exija mais de 256 cores pode ser convertido em um PNG de 8 bits com uma paleta de cores. Isso resulta em uma imagem com a mesma qualidade, mas que requer menos memória. Como resultado, os binários de imagem colocados nesse diretório podem mudar durante a compilação. Se você pretende ler uma imagem como bitstream para convertê-la em um bitmap, coloque suas imagens na pasta res/raw/
, onde a ferramenta aapt
não as modifica.
O snippet de código a seguir mostra como criar uma ImageView
que usa uma imagem criada a partir de um recurso drawable e a 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
, como mostrado no exemplo a seguir:
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);
Observação: cada recurso exclusivo no seu projeto pode manter apenas um estado, independentemente de quantos objetos distintos você instancie para ele. Por exemplo, se você instanciar dois objetos Drawable
do mesmo recurso de imagem e mudar uma propriedade (como a Alfa) de um dos objetos, o outro também será afetado. Ao lidar com várias instâncias de um recurso de imagem, em vez de transformar diretamente o objeto Drawable
, faça uma animação de interpolaçã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 fonte dos seus drawables, verifique se as imagens têm o tamanho adequado para várias densidades de pixel. Se as imagens não estiverem corretas, elas serão ampliadas, o que pode gerar artefatos nos seus drawables. Para ver mais informações, leia Compatibilidade com densidades de pixel diferentes.
Criar drawables a partir de recursos XML
Se você quiser criar um objeto Drawable
que não depende inicialmente de variáveis definidas pelo seu código ou interação do usuário, a definição de Drawable
em XML será uma boa opção. Mesmo que você espere que Drawable
mude as propriedades durante a interação do usuário com seu app, considere a possibilidade de definir o objeto em XML, já que você poderá modificar as propriedades depois que elas forem instanciadas.
Depois de definir seu Drawable
em XML, salve o arquivo no diretório res/drawable/
do projeto. O exemplo a seguir mostra o XML que define um recurso TransitionDrawable
, que herda 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 transmitindo o código do recurso do seu arquivo XML. Qualquer subclasse Drawable
compatível com o método inflate()
pode ser definida em XML e instanciada pelo seu app. Cada classe de drawable compatível com a inflação XML usa atributos XML específicos que ajudam a definir as propriedades do objeto. O código a seguir instancia o 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 listadas acima.
Drawables de formato
Um objeto ShapeDrawable
pode ser uma boa opção quando você quer desenhar dinamicamente um gráfico bidimensional. É possível desenhar formas básicas de maneira programática em um objeto ShapeDrawable
e aplicar os estilos de que seu app precisa.
ShapeDrawable
é uma subclasse de Drawable
. Por isso, você pode usar um ShapeDrawable
onde quer que um Drawable
seja esperado. Por exemplo, é possível usar um objeto ShapeDrawable
para definir o plano de fundo de uma visualização passando-o para o método setBackgroundDrawable()
da visualização. Você também pode desenhar sua forma como a própria visualização personalizada e adicioná-la a um layout no app.
Como ShapeDrawable
tem o próprio método draw()
, é possível criar uma subclasse de View
que desenhe o objeto ShapeDrawable
durante o evento onDraw()
, conforme mostrado no exemplo de código a seguir:
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); } }
É possível usar a classe CustomDrawableView
na amostra de código acima, como seria feito com qualquer outra visualização personalizada. Por exemplo, você pode adicioná-la de forma programática a uma atividade no app, como mostrado no exemplo a seguir:
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ê quiser usar a visualização personalizada no layout XML, a classe CustomDrawableView
precisará modificar o construtor View(Context, AttributeSet)
, que é chamado quando a classe é inflada do XML. O exemplo a seguir mostra como declarar a CustomDrawableView
no layout XML:
<com.example.shapedrawable.CustomDrawableView android:layout_width="fill_parent" android:layout_height="wrap_content" />
A classe ShapeDrawable
, como muitos outros tipos de drawable no pacote android.graphics.drawable
, permite definir várias propriedades do objeto por meio de métodos públicos. Alguns exemplos de propriedades que você pode usar 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 Recursos drawables.
Drawables NinePatch
Um gráfico NinePatchDrawable
é uma imagem bitmap esticável que pode ser usada como plano de fundo de uma visualização. 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 pelos botões padrão do Android. Os botões precisam ser esticados para acomodar strings de vários tamanhos. Um 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 diretório res/drawable/
do projeto.
Use a borda para definir as áreas esticáveis e estáticas da imagem. Indique uma seção esticável desenhando uma ou mais linhas pretas com 1 pixel de largura nas partes esquerda e superior da borda (os outros pixels de borda devem ser totalmente transparentes ou brancos). Você poderá usar quantas seções esticáveis quiser. O tamanho relativo das seções esticáveis não muda. Assim, a seção mais extensa será sempre a maior.
Também é possível definir uma seção de drawable opcional da imagem (linhas de preenchimento) desenhando uma linha à direita e outra na parte inferior. Se um objeto View
definir o gráfico NinePatch como plano de fundo e especificar o texto da visualização, ele se esticará para que todo o texto ocupe somente a área designada pelas linhas direita e inferior (se forem incluídas).
Se as linhas de preenchimento não forem incluídas, o Android usará as linhas esquerda e superior para definir essa área do drawable.
Para esclarecer a diferença, as linhas esquerda e superior definem quais pixels da imagem podem ser replicados para esticar a imagem. As linhas inferior e direita definem a área relativa dentro da imagem que o conteúdo da visualização pode ocupar.
A Figura 1 mostra um exemplo de gráfico NinePatch usado para definir um botão:

Figura 1: exemplo de um gráfico NinePatch que define um botão.
Esse gráfico NinePatch define uma área esticável com as linhas superior e esquerda, e a área do drawable com as linhas inferior e direita. Na imagem superior, as linhas cinza pontilhadas identificam as regiões que são replicadas para esticar a imagem. O retângulo rosa na imagem inferior identifica a região em que o conteúdo da visualização é permitido. Se o conteúdo não couber nessa região, a imagem será esticada para ajustá-lo.
A ferramenta Draw 9-patch oferece uma maneira muito prática de criar suas imagens NinePatch por meio de um editor gráfico WYSIWYG. Ele também gerará alertas se a região que você definiu para a área esticável estiver em risco de produzir artefatos de desenho como resultado da replicação de pixels.
A amostra de XML de layout a seguir demonstra como adicionar um gráfico NinePatch a alguns botões. A imagem do NinePatch é salva em 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"/>
Observe que os atributos layout_width
e layout_height
são 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 a partir do XML e da imagem do NinePatch mostrada acima. Observe como a largura e a altura do botão variam de acordo com o texto, e a imagem de plano de fundo é esticada para acomodá-lo.

Figura 2: botões renderizados por meio de um recurso XML e de 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 ele disponibiliza o objeto Canvas
necessário para oferecer 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; } }
Então, você poderá adicionar o drawable onde quiser. Por exemplo, a 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 (API nível 24) e versões posteriores, também é possível definir instâncias do drawable personalizado com XML das seguintes maneiras:
- Use o nome de classe totalmente qualificado como o nome do elemento XML. Para essa abordagem, a classe de drawable personalizado precisa ser pública de nível superior:
<com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android" android:color="#ffff0000" />
- Use
drawable
como o nome da tag XML e especifique o nome de classe totalmente qualificado a partir do atributo da 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 nível 21) e versões posteriores, é possível colorir os bitmaps e os nine-patches definidos como máscaras Alfa. Para fazer isso, use recursos de cor ou atributos de tema que indiquem esses recursos, como ?android:attr/colorPrimary
. Em geral, você deve criar esses recursos apenas uma vez e colori-los automaticamente para corresponder ao seu tema.
Você pode aplicar uma tonalidade aos objetos BitmapDrawable
, NinePatchDrawable
ou VectorDrawable
com o método setTint()
. Também é possível definir a cor e o modo da tonalidade nos seus layouts com os atributos 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 Como selecionar cores com a API Palette.