A drawable resource is a general concept for a graphic that can be drawn to the screen. Drawables are used to define shapes, colors, borders, gradients, etc. which can then be applied to views within an Activity
.
This is typically used for customizing the view graphics that are displayed within a particular view or context. Drawables tend to be defined in XML and can then be applied to a view via XML or Java.
Every drawable is stored as individual files in one of the res/drawable folders. Drawables are referred to in XML via @drawable/filename whereby filename is the filename without the file extension.
<TextView android:id="@+id/tvTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/filename" android:text="@string/greeting" />
In code you can also assign drawables to views. Most views accept an resource ID as input parameter. For example the following code shows how to set a drawables as background to an ImageView
.
ImageView imageView = (ImageView) findViewById(R.id.image); imageView.setImageResource(R.drawable.hello);
Sometimes it's useful to get the name of drawable (for example, R.drawable.recource_name
)
getResources().getIdentifier("recource_name","drawable", getPackageName())
and vice versa
String resName = "recource_name"; int resID = getResources().getIdentifier(resName , "drawable", getPackageName());
There are several different types of drawables:
BitmapDrawable
.NinePatchDrawable
.LayerDrawable
.StateListDrawable
.LevelListDrawable
.TransitionDrawable
.View
needs a background drawble that is smaller than the View
's actual bounds.ClipDrawable
.ScaleDrawable
.ShapeDrawable
.There are five drawables that are most important to know:
stroke
, fill
, and padding
.Let's explore these drawable file types one by one and take a look at examples of usage.
Bitmap Drawables
Using XML, we can define some rules around which a smaller image should be stepped and repeated to make a pattern. This can be a great way to make full-screen background images that don’t require a large Bitmap
to be loaded into memory. Applications can create a pattern by setting the tileMode
attribute on a <bitmap>
element to one of the following values:
Clamp
. The source bitmap will have the pixels along its edges replicated.Repeat
. The source bitmap will be stepped and repeated in both directions.Mirror
. The source bitmap will be stepped and repeated, alternating between normal and flipped images on each iteration and along each axis.Following is file res/drawable/pattern_stripes.xml
<?xml version="1.0" encoding="utf-8"?> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="@drawable/stripes" android:tileMode="mirror" />
Tinting Drawable elements
Sometimes you want to avoid duplicating common assets that vary only by color by dynamically coloring a baseline asset at runtime. There are two ways for it.
Drawable
instance. Drawable
color filters are typically fully opaque, but the framework also supports partial blending via PorterDuff.XferMode
. This method can be executed only from Java code.Drawable
instance via android:tint
in XML or setTint()
from Java code. In this case, blending can be applied via android:tintMode
or setTintMode()
either of which takes a Porter-Duff constant to represent the transfer mode.For a Porter-Duff color blend to apply correctly, areas of the icons that should not be modified need to be fully transparent, not solid white. The remaining pixels don't need to be black, but they must be fully opaque.
Following listing shows us the simple layout used to place these images into the activity.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="5dp"> <ImageView android:id="@+id/ivMessage1" android:layout_width="200dp" android:layout_height="wrap_content" android:src="@drawable/message_bg" android:layout_alignParentRight="true"/> <ImageView android:id="@+id/ivMessage2" android:layout_width="200dp" android:layout_height="wrap_content" android:src="@drawable/message_bg" android:layout_alignParentLeft="true" android:layout_below="@id/ivOriginal"/> </RelativeLayout>
Following listing shows us an activity with the code to tint the icons.
public class TintActivity extends AppCompatActivity { ImageView ivMessage1, ivMessage2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tint); ivMessage1 = (ImageView) findViewById(R.id.ivMessage1); ivMessage1.getDrawable().mutate().setColorFilter(0xFFFF0000, PorterDuff.Mode.SRC_ATOP); //ivMessage1.setColorFilter(ContextCompat.getColor(getContext,R.color.COLOR_YOUR_COLOR)); ivMessage2 = (ImageView) findViewById(R.id.ivMessage2); ivMessage2.getDrawable().mutate().setColorFilter(0xFF00FF00, PorterDuff.Mode.SRC_ATOP); //ivMessage2.setColorFilter(Color.argb(255, 255, 255, 255)); } }
Using the setColorFilter()
method, any Drawable
can be drawn with a tint. The simplest version of this method (which we have used here) accepts the ARGB color value and a PorterDuff.Mode
for pixel transfer and blending. Our choice of SRC_ATOP
ensures that the chosen color will be drawn fully and the original image pixel ignored.
If your base image has variations (for example, a gradient) that you would like to show through, pick a filter color that is partially transparent and/or try a different PorterDuff.Mode
value, such as MULTIPLY
.
Starting in Android 5.0, this same effect can be applied to drawables from XML by using the android:tint
attribute, or in code via setTint()
. Underneath your code, the framework is using the same technique you just saw, although slightly more efficiently since the framework can now share states that have a common tint.
Following listings redefine our icon assets as tinted drawables.
File res/drawable/tinted_bg.xml.
<?xml version="1.0" encoding="utf-8"?> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="@drawable/message_bg" android:tint="#FFAA00AA" />
Now when we insert these drawables into the activity layout, there is no further colorization work to do.
File res/layout/activity_tinted.xml.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="5dp"> <ImageView android:id="@+id/ivMessage1" android:layout_width="200dp" android:layout_height="wrap_content" android:src="@drawable/activity_tinted" android:layout_alignParentRight="true"/> </RelativeLayout>
Simple Activity
for tinted drawables.
public class TintActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tinted); } }
android:tint
attribute will only work on Lollipop and later API versions. How could we support older devices? There are two easy ways, one can choose any of them:
Use android.support.v4.graphics.drawable.DrawableCompat
.
Drawable drawable = getResources().getDrawable(R.drawable.message_bg); Drawable wrapped = DrawableCompat.wrap(drawable); wrapped.mutate(); // to not share its state with any other drawable DrawableCompat.setTint(wrapped, ContextCompat.getColor(getContext(), R.color.your_color));
Tint ImageView
manually.
ImageView ivMessage = (ImageView) findViewById(R.id.ivMessage1); ivMessage.setColorFilter(ContextCompat.getColor(context,R.color.COLOR_YOUR_COLOR), PorterDuff.Mode.SRC_ATOP);
Result
Shape Drawables
The Shape Drawable is an XML file that defines a geometric shape, including colors and gradients. This is used to create a complex shape that can then be attached as the background of a layout or a view on screen. For example, you can use a shape
drawable to change the shape, border, and gradient of a Button
background.
A shape is simply a collection of properties that are combined to describe a background. The shape can be described with properties such as corners
for rounding, gradient
for backgrounds, padding
for spacing, solid
for background colors, and stroke
for border.
Shape drawables provide four basic shapes: Rectangle, Oval, Line and Ring. From these shapes you can create an almost unlimited number of effects and styles for your application.
Solid Color Shapes
Here's an example of drawing a rounded rectangle with a border in res/layout/drawable/solid_color_shape.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="4dp" /> <stroke android:width="4dp" android:color="#C1E1A6" /> <solid android:color="#118C4E" /> <padding android:left="20dp" android:top="20dp" android:right="20dp" android:bottom="20dp" /> </shape>
and then applied to a TextView
using the background
property:
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/solid_color_shape" android:textColor="#ffffff" android:text="@string/greeting" />
and the resulting view looks like:
Note that drawables can be applied to any view and are usually set with the background
property referencing the drawable resource.
We can create a border programmatically
ShapeDrawable shape = new ShapeDrawable(new RectShape()); shape.getPaint().setColor(Color.RED); shape.getPaint().setStyle(Paint.Style.STROKE); shape.getPaint().setStrokeWidth(3); // Assign the created border to EditText widget view.setBackground(shape);
Gradient Colored Shapes
Shapes also support gradients backgrounds as well as supporting properties such as startColor
, centerColor
, endColor
, angle
. Different gradients such as radial
, linear
or sweep
can be selected using the type property.
Here's an example of a simple linear gradient shape specified in res/layout/drawable/gradient_shape.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <corners android:radius="4dp" /> <stroke android:width="1dp" android:color="#0078a5" /> <gradient android:startColor="#0078a5" android:endColor="#00adee" android:angle="90"/> <padding android:left="8dp" android:top="2dp" android:right="8dp" android:bottom="2dp" /> </shape>
applied to a Button
and the resulting view looks like:
On Android, colors are can be specified as RGB or ARGB. In RGB you have two characters for every color (red, green, blue), and in ARGB you have two additional chars for the alpha channel. Android uses hexadecimal ARGB values, which are formatted as #AARRGGBB. That first pair of letters, the AA, represent the alpha channel.
Following is some useful opacity values
We can create a gradient drawable programmatically
GradientDrawable gradient = new GradientDrawable(); gradient.setColors(new int[]{ Color.parseColor("#feffe9"), Color.parseColor("#fff600"), Color.parseColor("#feffe9"), }); gradient.setGradientType(GradientDrawable.LINEAR_GRADIENT); gradient.setShape(GradientDrawable.RECTANGLE); gradient.setStroke(2, Color.parseColor("#cbb700")); view.setBackgroundDrawable(gradient);
Line
Line is most often used as a visual separator between different sections or parts of the app and can make it easier to use. One important thing to note is that this line always takes up the entire width of the containing view.
First, let's look at the simplest example of a line, a simple solid-black line. Create res/drawable/shape_black_line.xml file.
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line"> <stroke android:width="2dp" android:color="#000000" /> <size android:height="2dp" /> </shape>
Apply in layout
<View android:layout_width="match_parent" android:layout_height="2dp" android:background="@drawable/line"/>
Some important things to keep in mind when creating a line:
stroke
element defines the height of the line.size
element defines the height of the entire drawable.It is also possible to create a dashed line. To do so, we specify the dashWidth
and dashGap
attributes on the stroke
element. Create res/drawable/shape_dotted_green_line.xml file.
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line"> <stroke android:width="2dp" android:color="#008000" android:dashWidth="3dp" android:dashGap="4dp"/> <size android:height="20dp" /> </shape>
Round badge
Layout
<TextView android:id="@+id/tvBadge" android:layout_width="50dp" android:layout_height="50dp" android:background="@drawable/badge_red" android:text="18" />
Drawable
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="#F00"/> <stroke android:width="2dp" android:color="#FFF"/> <padding android:top="10dp" android:right="15dp" android:left="15dp" android:bottom="10dp"/> </shape>
State List Drawables
A StateListDrawable
is a drawable object defined in XML that uses several different items to represent the same graphic, depending on the state of the object. For example, a Button
widget can exist in one of several different states (pressed, focused, or neither) and, using a state list drawable, you can provide a different background image for each state. The state list supports different view states such as android:state_pressed
, android:state_focused
, android:state_enabled
, android:state_selected
, among many others. The illustration below shows all the major states that can be represented:
For example, a state list XML for a Button
background might look like the following in a file such as res/drawable/selector_button_bg:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:state_enabled="true" android:drawable="@drawable/button_pressed" /> <item android:state_focused="true" android:state_enabled="true" android:drawable="@drawable/button_focused" /> <item android:state_enabled="true" android:drawable="@drawable/button_enabled" /> </selector>
Now, when the view (i.e Button
) is pressed or focused, the drawable used for the view will change accordingly. Note that any view can have a state selector, but the most common uses are with Button
s and ListView
items. There are also color state selectors which allow a color to be chosen based on view state such as in a file named res/color/button_text.xml:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:color="#ffff0000"/> <item android:state_focused="true" android:color="#ff0000ff"/> <item android:color="#ff000000"/> </selector>
and applied to textColor
property of a Button
in a layout file:
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/greeting" android:textColor="@color/button_text" />
Also we can use just shape
. Define layer-list
in res/drawable/button_gradient.xml.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape> <gradient android:type="linear" android:endColor="#6699CC" android:startColor="#99CCFF" android:angle="90.0" /> <corners android:radius="5.0dip" /> <padding android:left="20dip" android:right="20dip" android:top="7dip" android:bottom="7dip"/> </shape> </item> <item> <shape> <gradient android:type="linear" android:endColor="#336699" android:startColor="#99CCFF" android:angle="90.0" /> <corners android:radius="5.0dip" /> <padding android:left="20dip" android:right="20dip" android:top="7dip" android:bottom="7dip"/> </shape> </item> </selector>
Using state lists allows us to easily define dynamic views that respond to pressed, checked, enabled or other related states.
Following is example of use android:state_pressed
for EditText
.
Define selector
in res/drawable/et_style.xml.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:radius="4dp" /> <gradient android:startColor="#FF058bf5" android:endColor="#FF015ee6" android:angle="270" /> <stroke android:width="2px" android:color="#E6E6E6" /> </shape> </item> <item> <shape android:shape="rectangle"> <corners android:radius="4dp"/> <solid android:color="#FFFFFFFF" /> <stroke android:width="2px" android:color="#E6E6E6" /> </shape> </item> </selector>
In layout
<EditText android:id="@+id/et1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@drawable/triangle" android:hint="Username" android:padding="10dp" />
Layer List Drawables
A LayerDrawable
is a drawable object that manages an array of other drawables. Each drawable in the list is drawn in the order of the list - the last drawable in the list is drawn on top. Each drawable is represented by an <item>
element inside a single <layer-list>
element.
The LayerList
can be used to draw multiple other drawables (shapes, images, etc) and position them in relationship to one another. The layers are placed on top of one another by default with the last item being drawn on the top. Layers can then have their coordinates shifted using the left, right, top, and bottom properties.
Android triangle
Create arrow_up.xml file in drawables directory with contents:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <rotate android:fromDegrees="45" android:toDegrees="45" android:pivotX="-40%" android:pivotY="87%" > <shape android:shape="rectangle" > <stroke android:color="@android:color/transparent" android:width="10dp"/> <solid android:color="@android:color/holo_blue_light" /> </shape> </rotate> </item> </layer-list>
The idea is to create rectangle shape (<shape/>
), fill with gray solid color (<solid/>
), rotate it 45 degrees (<rotate/>
) and move it over X and Y axis (pivotX
and pivotY
) in a way that only half of the rectangle is visible (cut along the diagonal).
We also added thick border (<stroke/>
) with transparent color. This is because our arrow is a Button
, so the invisible part around is needed to ease the click (it enlarges click detection area size).
The usage is as simple as any other xml drawable shape. It is just enough to set it as view background
. Here is Button
example:
<Button android:layout_width="70dp" android:layout_height="70dp" android:background="@drawable/arrow_up" />
If you need arrow pointing in other direction, you can just rotate it. Here is arrow down:
<Button android:layout_width="70dp" android:layout_height="70dp" android:rotation="180" android:background="@drawable/arrow_up" />
Compared to png, icon is:
Card with shadow
A card is nothing more than a layout or a view with a background
drawable. And that drawable can be defined in res/drawable/layer_card_background.xml XML as a layer drawable.
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- bottom 2dp shadow --> <item> <shape android:shape="rectangle"> <solid android:color="#CABBBBBB"/> <corners android:radius="2dp" /> </shape> </item> <!-- white top color --> <item android:bottom="2dp"> <shape android:shape="rectangle"> <solid android:color="@android:color/white"/> <corners android:radius="2dp" /> </shape> </item> </layer-list>
The first item in the layer-list
defines what will be the card's shadow. The second item in the layer-list
is the main content for the card. You can turn any view or layout into a card by setting the background
to the layer_card_background drawable.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="#E0EEEE"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:layout_margin="15dp" android:padding="15dp" android:background="@drawable/layer_card_background" android:text="Lorem ipsum ..."/> </LinearLayout>
TextView with border at top and bottom
Create an xml drawable such as res/drawable/textlines.xml and assign this as a TextView
's background property.
In layout
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="My text with lines above and below" android:background="@drawable/textlines"/>
Define layer-list
in res/drawable/textlines.xml.
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape android:shape="rectangle"> <stroke android:width="1dp" android:color="#FF000000" /> <solid android:color="#FFDDDDDD" /> </shape> </item> <item android:top="1dp" android:bottom="1dp"> <shape android:shape="rectangle"> <stroke android:width="1dp" android:color="#FFDDDDDD" /> <solid android:color="#00000000" /> </shape> </item> </layer-list>
Button with border at bottom
Define layer-list
in res/drawable/button_stroke.xml.
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="rectangle" > <solid android:color="#1bd4f6" /> </shape> </item> <item android:top="-2dp" android:right="-2dp" android:left="-2dp"> <shape> <solid android:color="@android:color/transparent" /> <stroke android:width="1dp" android:color="#FF0000" /> </shape> </item> </layer-list>
In layout
<Button android:text="Submit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/button_stroke"/>
If you want to remove shadow for button add style="?android:attr/borderlessButtonStyle"
.
<Button android:text="Submit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/button_stroke" style="?android:attr/borderlessButtonStyle"/>
Button with shadow
In layout
<Button android:text="Submit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shadow"/>
Define layer-list
in res/drawable/shadow.xml.
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:bottom="4dp" android:right="4dp"> <shape> <gradient android:angle="-90.0" android:endColor="#006666" android:startColor="#339999" /> <corners android:radius="10dp" /> </shape> </item> <item android:left="4dp" android:top="4dp"> <shape> <solid android:color="#88339999" /> <corners android:radius="10dp" /> </shape> </item> </layer-list>
Several shapes
The following layer list draws several shapes in relation to each other:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape android:shape="rectangle"> <size android:width="280dp" android:height="140dp"/> <stroke android:width="1dp" android:color="#585858" /> <solid android:color="#FF9009" /> <padding android:bottom="1dp"/> </shape> </item> <item android:left="10dp" android:top="20dp" android:bottom="20dp" android:right="150dp"> <shape android:shape="oval"> <stroke android:width="1dp" android:color="#ffffff" /> <solid android:color="#118C4E" /> <padding android:bottom="1dp"/> </shape> </item> <item android:left="150dp" android:top="20dp" android:bottom="20dp" android:right="10dp"> <shape android:shape="rectangle"> <stroke android:width="1dp" android:color="#ffffff" /> <solid android:color="#C1E1A6" /> <padding android:bottom="1dp"/> </shape> </item> </layer-list>
In layout
<View android:layout_width="300dp" android:layout_height="170dp" android:background="@drawable/shape2"/>
and this results in the following:
Keep in mind that the items in a LayerList
can also be images or any other type of drawable. You can use this to create more complex drawings and overlay multiple drawables on top of each other.
Nine-Patch Drawables
A NinePatch is a PNG image in which you can define stretchable regions that are stretched when the content within the View
exceeds the normal image bounds. You typically assign this type of image as the background
of a View
which has its width set to wrap_content
. The most common use is a Button
that has to stretch based on the text displayed inside.
As you can see, you have guides on each side of your image. The top and left guides are for scaling your image, while the right and bottom guides define the fill area. The top and left guides are used to define the scalable portion of your image - left for scaling height, top for scaling width. Using a Button
image as an example, this means the Button
can stretch horizontally and vertically within the black portion and everything else, such as the corners, will remain the same size.
So, a valid nine-patch image file is simply a PNG image in which the outer 1 pixel contains only either black or transparent pixels. The black pixels on each side define something about how the image will stretch and wrap the content inside:
The black guide lines are cut-off/removed from your image - they won't show in the app. Guides must only be one pixel wide, so if you want a 48x48 button, your png will actually be 50x50. Anything thicker than one pixel will remain part of your image. Your guides must be solid black (#000000). Also you should keep in mind that remaining area of the one-pixel outline must be completely transparent. This includes the four corners of the image - those should always be clear.
Fill area guides are optional and provide a way define the area for stuff like your text label. Fill determines how much room there is within your image to place text, or an icon, or other things.
NinePatch are images that have a .9.png file extension, which signifies that this is a stretchable PNG image. The file is no different from a normal PNG file except that you will add thin black lines to indicate the vertical and horizontal "stretchable" and "fill" areas for the image. Android will not show these guide lines, which are used to determine how the image should be rendered.
An example of a 9-patch image is embedded below (left is the 9patch graphic, right is an example of use in an app):
A NinePatch is defined and saved in the drawable folder and setting the background works the same as with any image:
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Submit" android:background="@drawable/button_background"/>
Android Studio comes with the ability to edit 9-patch files directly. Your PNG file simply needs to be saved with the .9.png extension in the drawable folder, and the 9-patch editor will display instead of the normal image editor. You can use the mouse to select the regions to be stretched (use Shift and click while dragging the mouse to erase the region), and the preview pane on the right displays how images will be rendered depending on the text inside.
Transition Drawables
Transition Drawables allow to define transitions which lets us display a smooth cross-fade effect between two pictures, for example.
Firstly, we'll need to add 2 pictures to the drawable directory of the project. In my case, they are cat1.jpg and cat2.jpg, and I put both of them in res/drawable-hdpi/ directory.
Add an xml file in the same directory, call it transition.xml. Here we will add a transition node with 2 item nodes inside, each representing an image:
<?xml version="1.0" encoding="utf-8"?> <transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/cat1" /> <item android:drawable="@drawable/cat2" /> </transition>
Now go to activity_main.xml layout file. Add an ImageView
, set its source to the first image:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/ivCat" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/cat1"/> </LinearLayout>
When that's done, go to MainActivity.java class and declare 2 variables - instances of ImageView
and TransitionDrawable
.
private ImageView ivCat; private TransitionDrawable trans;
In the onCreate()
function of the Activity, set the image value to the ImageView
we declared in activity_main.xml. Set trans
value to the transition resource we created in the drawable directory:
image = (ImageView)findViewById(R.id.ivCat); Resources res = this.getResources(); trans = (TransitionDrawable) res.getDrawable(R.drawable.transition);
Now add a click listener to the ImageView
object. In the event of a click, use the setImageDrawable()
method to apply the transition resource to the image. Then we call the reverseTransition()
method of the transition, passing 1000 as the parameter, which is the effect time.
ivCat.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ivCat.setImageDrawable(trans); trans.reverseTransition(1000); } });
Instead of reverseTransition()
, you can call startTransition()
, which always starts with the first layer fading out and the second layer fading it. The reverseTransition()
method handles the transition both ways.
Level List
Using level list drawable, drawable attributes of a view can be set to deferent drawables at run time by calling setLevel on Drawable
object and passing level value to it. The level value points to a drawable in the level list drawable.
You can define level list drawable xml with different drawable items setting max and min values for each drawable. At run time, depending on the value passed to setLevel
method, a drawable from the level drawable list will be picked and displayed.
Below example defines level list xml with three dawable items with different levels and level ranges. On clicking a button, level is incremented by calling setLevel on Drawable
that will make it show corresponding drawable from the level list. Every time the button is clicked, image will be changed to reflect level value.
Drawable
<?xml version="1.0" encoding="utf-8"?> <level-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/square_red" android:maxLevel="0" /> <item android:drawable="@drawable/square_blue" android:maxLevel="1" /> <item android:drawable="@drawable/square_green" android:minLevel="2" android:maxLevel="4"/> </level-list>
Layout xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_margin="8dp" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/level_list"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dp" android:text="Button"/> </LinearLayout>
Activity
public class MainActivity extends AppCompatActivity { private int levelInt = 0; private ImageView img; private Drawable drawable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); drawable = getResources().getDrawable(R.drawable.level_list); img = findViewById(R.id.img); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (levelInt >= 4){ levelInt = 0; } else { levelInt++; } drawable.setLevel(levelInt); img.setImageDrawable(drawable); img.refreshDrawableState(); } }); } }
Scale Drawable
Using scale drawable, you can specify how a drawable can be scaled depending on the level by setting scale height, scale width and scale gravity. Below is an example scale drawable which is displayed in image view. On clicking a button, the drawable’s level will be increased by calling setLevel
and passing level. As the level increases, the drawable that is displayed in ImageView
will scale.
Drawable
<?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/zoftino" android:scaleGravity="center_vertical|center_horizontal" android:scaleHeight="60%" android:scaleWidth="60%" />
Activity
img = findViewById(R.id.img); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ScaleDrawable drawable = (ScaleDrawable) img.getDrawable(); levelInt = levelInt +800; drawable.setLevel(levelInt); } });