What is the difference between these three xml files in android?
xml file with selector as root element
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<Further Designing ... />
...
</shape>
</item>
</selector>
xml file with shape as root element
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<Further Designing ... />
...
</shape>
xml file with layer-list as root element
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<Further Designing ... />
...
</shape>
</item>
<item android:bottom="1dp">
<shape android:shape="rectangle">
<Further Designing ... />
...
</shape>
</item>
</layer-list>
Which one is used in which case. A little examples will be more appreciated. Thanks!!!
Layer List
From docs:
A Drawable that manages an array of other Drawables. These are drawn in array order, so the element with the largest index is be drawn on top. Creates a LayerDrawable.
This is used when you want to combine multiple drawables into one, for example you could use it to add a background to an icon.
Selector (StateList)
From docs:
A StateListDrawable is a drawable object defined in XML that uses a several different images 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.
It can used to show different drawables in different conditions.
Shape
From docs:
An XML file that defines a geometric shape, including colors and gradients. Creates a GradientDrawable.
This should be used when you want to show a single shape. It can be used inside a LayerList to add a shape to an image or it can be used with a selector to switch between shapes as well.
Fun Part(hopefully)
All 3 of these represent drawables so you can combine these to meet your needs. For example I could have selector as root element, which contains LayerList and each layer list can have shapes.
When working with these dynamically, all 3 are subclasses of Drawable class.
Check out documentation for more information:
https://developer.android.com/guide/topics/resources/drawable-resource
Selectors let you employ different drawables or shapes depending on state (like, pressed, checked, etc.). Use them, for example, when you want a pressed state and a non-pressed state for buttons.
Shape lets you draw simple shapes, and apply border radius, colors, gradients, etc. to them.
Layer-list lets you layer drawables on top of each other to create composite drawables. For example, a common way to create a bordered background is to create a layer-list with a rectangle as one item and a slightly smaller rectangle (with 1dp padding, say) inside of it. The larger rectangle is your border outline.
Related
I have a simple button
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/add"
android:backgroundTint="#color/add_bg"
android:textColor="#color/add_fg"
<!--android:borderColor?="#color/button_border"-->
android:text="#string/add"/>
I would like to have white background, blue text and blue border around. I am aware that I can achieve that through a drawable as shown here and in numerous other places. However I have observed that if you add a drawable to the button then it will lose all of its material properties (such as shadow and also upon clicking having the fancy ripple animation). So how would I add a border around the button without losing the material theme animations (shadow and tipple animation on click)?
Most of the items that android comes with are simply a pre-packaged set of attributes.
It would be almost impossible to expect the Android API developers to include a pre-packaged set of attributes for every possible color/border combination, but there is always a solution!
Unfortunately,as you mentioned, the solution does reside in creating your own custom XML file which can often be intimidating until you get the hang of it. Once you do, you too will marvel at the flexibility it allows.
Specifically for your situation, there are two options...
1) Create a custom XML border drawable.
2)under your buttons background property set your new custom border drawable
3)then also set the ripple effect under your buttons xml properties by adding:
android:foreground="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
----OR----
A more complex way is to make a drawable like the one below. This will add the "ripple" button effect as well as a custom shadow, button color, and border color!
"For anybody reading this later that may be less experienced)
1)In your project view go to res/drawable
2)right click the folder itself and select new/drawable resource file
3)Enter a file name my_ripple_button.xml(the root doesn't really matter because you wil replace it with the below code)
4)Click on the text tab if you aren't already there
5)select all text and basically replace with the following: (creating a custom color border is basically the same steps)
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorPrimaryDark">
<item android:id="#android:id/ripple">
<shape android:shape="rectangle">
<solid android:color="#color/colorPrimaryDark" />
<corners android:radius="#dimen/button_radius_large" />
</shape>
</item>
<item android:id="#android:id/background">
<shape android:shape="rectangle">
<gradient
android:angle="90"
android:endColor="#color/colorPrimaryLight"
android:startColor="#color/colorPrimary"
android:type="linear" />
<corners android:radius="#dimen/button_radius_large" />
</shape>
</item>
</ripple>
After the call of EditText.setBackgroundColor(Color.RED) I see only a red rectangle with text inside it, but I want to change only the text background and to keep the standard bottom border which is grey when the field has no focus and blue if it has focus. Can I do it programmatically?
I want to change the text background to red if the input is invalid and to transparent if it is valid.
I think the best way is to work with drawable/shape.xml as background and upon logic code situation call EditText.setBackground(some_other_shape.xml). Here is an example for shape file xml demonstrating how to use:
Border color ("stroke"): In this example some custom color from colors.xml
Fill color ("solid"): In this example Android default transparent color
Even image icon inside
<!--Example for custom shape file xml design-->
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#mipmap/icon_image" />
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#android:color/transparent" />
<stroke android:width="1dp" android:color="#color/orange_primary" />
</shape>
</item>
</layer-list>
So just prepare several shapes for each situation you need. Another approach is to work with layout params etc. but I think this one is faster and gives more control for custom design in easy to understand code.
I can't dig deep into how android implements its layer-list drawable. But I find it interesting and I can hardly know why this happens.
Here are some drawables:
the nine-patch xml
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/cam2tst_ripple_bg_img">
</nine-patch>
the shape xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<padding
android:left="#dimen/cam2tst_ripple_horizontal_padding"
android:top="#dimen/cam2tst_ripple_vertical_padding"
android:right="#dimen/cam2tst_ripple_horizontal_padding"
android:bottom="#dimen/cam2tst_ripple_vertical_padding" />
<solid android:color="#android:color/holo_green_dark" />
</shape>
the ripple xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#android:color/holo_green_light">
<item android:drawable="#drawable/cam2tst_ripple_shape"></item>
</ripple>
the layer-list containing all above
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/cam2tst_ripple_bg_img" />
<item android:drawable="#drawable/cam2tst_ripple_base" />
</layer-list>
Unfortainately I still can't get my screenshot thing work on my L preview, but I can describe it.
What I get is the shape (which i obviously didn't set its size explicitly) doesn't cover over the whole nine-patch! The un-streched part of the nine-patch is magically considered as some kind of "auto padding thing". What I was expecting (ok I was expecting exactly what android has done for me, I mean what I was... supposing...) is something not so positive: the not-particularly-sized shape drawable covering the entire nine-patch just as if the latter is a normal png.
But the shape does magically avoid the un-stretched part of the nine-patch and overlays only above the streched-part of the nine-patch.
This is awesome...but confusing, why? I may not able to dig that deep into the source but this do sounds anti-intuition (but nice). I want to know the reason though. So I post this here.
Since I tagged this as android-L because I am working on one. But I think this shall be working from something like gingerbread.(just to replace the ripple drawable with something else, maybe a inset drawable etc.)
This effect is caused by the combination of two things:
All nine-patch drawables have a padding area defined automatically from the edges of the content area. The content area can be defined either explicitly, using the right and bottom lines at the border, or implicitly from the stretchable area defined by the left and top lines.
Layer-list applies the padding on each layer cumulatively to the next layer by default*, effectively treating each layer as the content of the previous layer.
* Lollipop has introduced a new attribute for disabling this behavior.
I was trying to apply shadow effect for my views and find out that I could use gradient to do it.
I created an XML file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:endColor="#android:color/transparent"
android:centerColor="#android:color/transparent"
android:startColor="#android:color/black"
android:angle="135"/>
</shape>
This works fine, but I needed to make it more like a shadow.
What I need is to remove the transition effect in gradient because I only need two colors in one view applied diagonally. How to do it?
If you want that to be something like tha background of your views, why don't you just save a B/W .jpeg or .png image inside your Drawables and use it when needed specifying its dimensions and alpha (opacity) parameter?
In that case I'd suggest using nine-patch drawables
I have a Button that looks according to the Theme.Holo.Light. I used to round its corners by setting its background to the following:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="10dp"
android:shape="rectangle" >
<corners
android:bottomLeftRadius="15dp"
android:bottomRightRadius="15dp"
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
</shape>
Now the Button becomes transparent. I tried to create a selector, add a solid attribute and use 2 of such drawables for normal and pressed states, but I could not copy the default Button behavior of the Holo.Light theme. So I'm looking for 2 possible solutions: either somehow round the Button's corners without affecting its default Style or find the XML defining the mentioned style so I can copy it. I've been looking inside the SDK and using this reference: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/themes.xml but did not succeed.
Any ideas how to make a rounded corners Button BUT keep all the other appearance attributes to their defaults?
The original style uses 9 patches.
If you read THIS document and search for btn_default (beginning at line 1995), you will learn how to make a style that overrides the standard drawables (9 patches).
Then it's just a matter of copying the original artworks to your app's drawable folders and round their corners.
They'll be referred in a StateList drawable, called btn_default_holo_light.xml
If you're using Windows, it's here: C:\Your_Path_To_Eclipse\sdk\platforms\android-XY\data\res\drawable, where XY is 11 to 19 (depending on you minSdkVersion)
And the 9 patches here: C:\Your_Path_To_Eclipse\sdk\platforms\android-XY\data\res\drawable-RES, where XY is 11 to 19 (depending on you minSdkVersion) and RES is the specific dpi resolution (mdpi, as a reference)