Android selector with background image and gradient - android

I know there are similar post to this but I couldn't find my answer in any of them. So, I have this drawable XML:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<bitmap
android:src="#drawable/bm_btn_background"
android:tileMode="repeat"
android:gravity="center" />
</item>
<item android:state_enabled="true">
<shape android:shape="rectangle">
<gradient
android:startColor="#a0e0b071"
android:endColor="#a0a67637"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#5c3708" />
<corners
android:radius="5dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
<item android:state_pressed="true" >
<shape>
<gradient
android:startColor="#a0a67637"
android:endColor="#a0e0b071"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#5c3708" />
<corners
android:radius="5dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
I am trying to create a button with a repeated image as background and a gradient applied to it. With this code I only see the background image, not the gradient nor the border and the rounded corners. Also, when I click the button, it doesn't change (the gradient is supposed to change). I don't know what is wrong with this code? If instead of a selector I use a layer-list, I get the desired result but it doesn't change either when I press the button. Thanks for your help!

Your code for the selector is wrong because:
You have two elements for the same state and as the selector encounters the first state(state_enabled) for the Bitmap element it will stop there and your gradient will never appear(for this you should use a layer-list that has as items the Bitmap and the gradient on top)
The selector will match states in order. As you press the Button the state_pressed will never be activated because the selector will match first the state_enabled that is on the first element(for this you should move the code for the state_pressed above the state_enabled elements).
In fact you should just remove the state_enabled and let the Bitmap + gradient be the default value for the Button. Bellow is your selector(I assumed you only want to change gradient on the image(but the image should appear even in the pressed state, if this isn't the wanted behavior leave only the gradient for the state_pressed)):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<layer-list>
<item>
<bitmap android:gravity="center" android:src="#drawable/bm_btn_background" android:tileMode="repeat" />
</item>
<item>
<shape>
<gradient android:angle="270" android:endColor="#a0e0b071" android:startColor="#a0a67637" />
<stroke android:width="1dp" android:color="#5c3708" />
<corners android:radius="5dp" />
<padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
</shape>
</item>
</layer-list>
</item>
<item android:state_enabled="true">
<layer-list>
<item>
<bitmap android:gravity="center" android:src="#drawable/bm_btn_background" android:tileMode="repeat" />
</item>
<item>
<shape android:shape="rectangle">
<gradient android:angle="270" android:endColor="#a0a67637" android:startColor="#a0e0b071" />
<stroke android:width="1dp" android:color="#5c3708" />
<corners android:radius="5dp" />
<padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
</shape>
</item>
</layer-list>
</item>
</selector>

Take a look on your state attrubute
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Non focused states -->
<item android:drawable="#drawable/nicebuttonround" android:state_focused="false" android:state_pressed="false" android:state_selected="false"/>
<item android:drawable="#drawable/nicebuttonround" android:state_focused="false" android:state_pressed="false" android:state_selected="true"/>
<!-- Focused states -->
<item android:drawable="#drawable/nicebuttonroundi" android:state_focused="true" android:state_pressed="false" android:state_selected="false"/>
<item android:drawable="#drawable/nicebuttonroundi" android:state_focused="true" android:state_pressed="false" android:state_selected="true"/>
<!-- Pressed -->
<item android:drawable="#drawable/nicebuttonroundi" android:state_pressed="true" android:state_selected="true"/>
<item android:drawable="#drawable/nice22i" android:state_pressed="true"/>
</selector>
For repeating background as image you just have to create 9 pitch images.

in my case i am using this. try it
<item android:state_pressed="true">
<shape>
<solid android:color="#color/mediumGray" />
<stroke
android:width="1px"
android:color="#color/darkGray" />
<padding
android:bottom="2dp"
android:left="1dp"
android:right="1dp"
android:top="2dp" />
<corners
android:bottomLeftRadius="7sp"
android:bottomRightRadius="7sp"
android:topLeftRadius="7sp"
android:topRightRadius="7sp" />
</shape>
</item>
<item android:state_focused="true">
<shape>
<solid android:color="#color/mediumGray" />
<stroke
android:width="1px"
android:color="#color/darkGray" />
<padding
android:bottom="2dp"
android:left="1dp"
android:right="1dp"
android:top="2dp" />
<corners
android:bottomLeftRadius="7sp"
android:bottomRightRadius="7sp"
android:topLeftRadius="7sp"
android:topRightRadius="7sp" />
</shape>
</item>
<item>
<shape>
<solid android:color="#color/lightGray" />
<stroke
android:width="1px"
android:color="#color/blackTransparent" />
<padding
android:bottom="2dp"
android:left="1dp"
android:right="1dp"
android:top="2dp" />
<corners
android:bottomLeftRadius="7sp"
android:bottomRightRadius="7sp"
android:topLeftRadius="7sp"
android:topRightRadius="7sp" />
</shape>
</item>

I have added extra transperent space to the right side of image using photoshop canvas size option and it works fine for me. download below image to see demo.

Related

Is it possible to have multiple borders on a shape?

I was wondering if it is possible to have multiple borders/"stroke" elements on a shape, or if I need to use an image (or a bunch of shapes covering each other). My code:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:endColor="#color/editTextBG"
android:startColor="#color/editTextBG"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#color/editTextEdgeInner" />
<stroke
android:width="1dp"
android:color="#color/editTextEdgeCenter" />
<stroke
android:width="1dp"
android:color="#color/editTextEdgeOuter" />
<corners
android:radius="3dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
</selector>
I've tried just using the code, which didn't work, and giving the earlier strokes a bigger width (so that the later, if drawn over, would only color part). However, it seems the last stroke overrides the others?
A workaround for borders is to overlay elements:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="#color/colorAccent"/>
</item>
<item android:top="8dp">
<color android:color="#color/colorPrimaryDark"/>
</item>
<item android:top="16dp">
<color android:color="#color/colorPrimary"/>
</item>
<item android:top="32dp" android:right="8dp">
<color android:color="#android:color/holo_red_dark"/>
</item>
</layer-list>
This is the result:
The first element in the layer-list from top to bottom is the background and every other is mounted on top.
<item>
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="#color/colorWhite" />
<stroke
android:width="1dp"
android:color="#979797" />
</shape>
</item>
<item
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="#ffd400" />
</shape>
</item>

Changing background color for TableRows when pressed

I created an xml-file (drawable) for my TableRow layout, which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape>
<solid
android:color="#03114e" />
<stroke
android:width="1dp"
android:color="#2f6699" />
<corners
android:radius="3dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
<item>
<shape>
<solid
android:color="#829fbc" />
<stroke
android:width="1dp"
android:color="#17456b" />
<corners
android:radius="3dp" />
<padding
android:left="6dp"
android:top="6dp"
android:right="6dp"
android:bottom="6dp" />
</shape>
</item>
</selector>
It's actually supposed to change the background of the TableRow when the user touches it. Unfortunately, nothing happens.
The default background (defined between the second item-tag) works perfectly well. However, the state_pressed argument has no use.
I even tried state_focused, but still without use.
Ideas?
You can't put <shape> inside <item>. You have to make the shapes separate drawables and define your selector drawable like this:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/table_row_pressed" />
<item android:drawable="#drawable/table_row_default" />
</selector>

XML drop shadow and different states

I'm trying to define a background for my ListView that has drop shadow and different colours for pressed state. Here's what I have.
<?xml version="1.0" encoding="utf-8"?>
<!-- Drop Shadow Stack -->
<item>
<shape>
<padding android:bottom="1dp"/>
<solid android:color="#00CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:bottom="1dp" />
<solid android:color="#10CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:bottom="1dp" />
<solid android:color="#20CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:bottom="1dp" />
<solid android:color="#30CCCCCC" />
</shape>
</item>
<item>
<shape>
<padding android:bottom="1dp" />
<solid android:color="#50CCCCCC" />
</shape>
</item>
<!-- Background -->
<item android:state_pressed="true">
<shape>
<solid android:color="#color/fublue" />
</shape>
</item>
<item android:state_activated="true">
<shape>
<solid android:color="#color/fublue" />
</shape>
</item>
<item>
<shape>
<solid android:color="#color/white" />
</shape>
</item>
However, that doesn't work. What do I need to change to get it working?
I'm not entirely sure what you're doing for the drop-shadow, but for the press states, you must make your list view item layouts clickable. And then create a background selector drawable for your push states.
Standard Style File
yourcolorstates.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:platformrq="http://schemas.android.com/apk/res-auto" >
<item
android:background="#yourneutralcolor"
android:state_pressed="false" />
<item
android:background="#yourpressedcolor"
android:state_pressed="true" />
</selector>
wrap the items in a state selector and the states need to be be set.
example
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_focused="true">
<shape>
...
</shape>
</item>
</selector>

Change Padding in Selector drawable

i am trying to change the padding from a Button in a custom drawable ressource, and reuse this in a selector.
Changing the drawable seems not the Problem, but the App always use the highest padding aviable from the different drawables:
button_inactive.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="#FF4d681f" />
</shape>
</item>
<item
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp">
<shape android:shape="rectangle" >
<solid android:color="#FFFFFFFF" />
<padding
android:bottom="5dp"
android:top="5dp" />
</shape>
</item>
button_active.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="#FF4D681F" />
</shape>
</item>
<item
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp">
<shape android:shape="rectangle" >
<solid android:color="#FF8da32d" />
<padding
android:bottom="10dp"
android:top="10dp" />
</shape>
</item>
button_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="false" android:drawable="#drawable/button_active"/>
<item android:state_focused="true" android:state_pressed="true" android:drawable="#drawable/button_active"/>
<item android:state_focused="false" android:state_pressed="true" android:drawable="#drawable/button_active"/>
<item android:drawable="#drawable/button_inactive"/>
The Problem is that my Button uses the 10dp padding in all states, including the "inactive" state.
Is there a Solution to get it working only with XML or it is better to make a custom Button programaticly?
try this
<solid android:color="#ffffff" />
<stroke
android:width="2dp"
android:color="#android:color/black" />
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
<corners
android:bottomLeftRadius="6dp"
android:bottomRightRadius="6dp"
android:topLeftRadius="6dp"
android:topRightRadius="6dp" />
Add android:variablePadding="true" attribute to your selector.
I'm not sure how (and if) is this working when you are using layer-list, however I decided to share it anyway for anyone looking for the answer (as I was).

How to provide shadow to Button

As you can see in image, I want shadow behind a Button. I have created Button with rounded corners. But problem is I can't generate a shadow behind that Button. How can I achieve this?
Use this approach to get your desired look.
button_selector.xml :
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<layer-list>
<item android:right="5dp" android:top="5dp">
<shape>
<corners android:radius="3dp" />
<solid android:color="#D6D6D6" />
</shape>
</item>
<item android:bottom="2dp" android:left="2dp">
<shape>
<gradient android:angle="270"
android:endColor="#E2E2E2" android:startColor="#BABABA" />
<stroke android:width="1dp" android:color="#BABABA" />
<corners android:radius="4dp" />
<padding android:bottom="10dp" android:left="10dp"
android:right="10dp" android:top="10dp" />
</shape>
</item>
</layer-list>
</item>
</selector>
And in your xml layout:
<Button
android:background="#drawable/button_selector"
...
..
/>
For android version 5.0 & above
try the Elevation for other views..
android:elevation="10dp"
For Buttons,
android:stateListAnimator="#anim/button_state_list_animator"
button_state_list_animator.xml - https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/anim/button_state_list_anim_material.xml
below 5.0 version,
For all views,
android:background="#android:drawable/dialog_holo_light_frame"
My output:
Here is my button with shadow cw_button_shadow.xml inside drawable folder
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<layer-list>
<!-- SHADOW -->
<item>
<shape>
<solid android:color="#color/red_400"/>
<!-- alttan gölge -->
<corners android:radius="19dp"/>
</shape>
</item>
<!-- BUTTON alttan gölge
android:right="5px" to make it round-->
<item
android:bottom="5px"
>
<shape>
<padding android:bottom="5dp"/>
<gradient
android:startColor="#1c4985"
android:endColor="#163969"
android:angle="270" />
<corners
android:radius="19dp"/>
<padding
android:left="10dp"
android:top="10dp"
android:right="5dp"
android:bottom="10dp"/>
</shape>
</item>
</layer-list>
</item>
<item android:state_pressed="true">
<layer-list>
<!-- SHADOW -->
<item>
<shape>
<solid android:color="#102746"/>
<corners android:radius="19dp"/>
</shape>
</item>
<!-- BUTTON -->
<item android:bottom="5px">
<shape>
<padding android:bottom="5dp"/>
<gradient
android:startColor="#1c4985"
android:endColor="#163969"
android:angle="270" />
<corners
android:radius="19dp"/>
<padding
android:left="10dp"
android:top="10dp"
android:right="5dp"
android:bottom="10dp"/>
</shape>
</item>
</layer-list>
</item>
</selector>
How to use. in Button xml, you can resize your height and weight
<Button
android:text="+ add friends"
android:layout_width="120dp"
android:layout_height="40dp"
android:background="#drawable/cw_button_shadow" />
If you are targeting pre-Lollipop devices, you can use Shadow-Layout, since it easy and you can use it in different kind of layouts.
Add shadow-layout to your Gradle file:
dependencies {
compile 'com.github.dmytrodanylyk.shadow-layout:library:1.0.1'
}
At the top the xml layout where you have your button, add to the top:
xmlns:app="http://schemas.android.com/apk/res-auto"
it will make available the custom attributes.
Then you put a shadow layout around you Button:
<com.dd.ShadowLayout
android:layout_marginTop="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:sl_shadowRadius="4dp"
app:sl_shadowColor="#AA000000"
app:sl_dx="0dp"
app:sl_dy="0dp"
app:sl_cornerRadius="56dp">
<YourButton
.... />
</com.dd.ShadowLayout>
You can then tweak the app: settings to match your required shadow.
Hope it helps.
I've tried the code from above and made my own shadow which is little bit closer to what I am trying to achieve. Maybe it will help others too.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<layer-list>
<item android:left="5dp" android:top="5dp">
<shape>
<corners android:radius="3dp" />
<gradient
android:angle="315"
android:endColor="#android:color/transparent"
android:startColor="#android:color/black"
android:type="radial"
android:centerX="0.55"
android:centerY="0"
android:gradientRadius="300"/>
<padding android:bottom="1dp" android:left="0dp" android:right="3dp" android:top="0dp" />
</shape>
</item>
<item android:bottom="2dp" android:left="3dp">
<shape>
<corners android:radius="1dp" />
<solid android:color="#color/colorPrimary" />
</shape>
</item>
</layer-list>
</item>
</selector>
Try this if this works for you
android:background="#drawable/drop_shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="3dp"
android:paddingTop="3dp"
android:paddingRight="4dp"
android:paddingBottom="5dp"
Sample 9 patch image with shadow
After a lots of research I found an easy method.
Create a 9 patch image and apply it as button or any other view's background.
You can create a 9 patch image with shadow using this website.
Put the 9 patch image in your drawable directory and apply it as the background for the button.
mButton.setBackground(ContextCompat.getDrawable(mContext, R.drawable.your_9_patch_image);
Since none of the answers here really address the question, I wanted to point out https://github.com/Devlight/ShadowLayout (not my project). This is a simple Android layout you can wrap around anything to give it a shadow. The library is a single class and only ~250 lines. The README says deprecated, but it works great.
Wrapping all your views isn't ideal, but until Android provides a standard mechanism to introduce a shadow, or you want to draw all of your button states as bitmaps that include the shadow pixels, this is the best option I could fine.
Adding the below 2 lines worked for me
android:elevation="10dp"
android:stateListAnimator="#null"
You can try this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<layer-list>
<item android:left="1dp" android:top="3dp">
<shape>
<solid android:color="#a5040d" />
<corners android:radius="3dip"/>
</shape>
</item>
</layer-list>
</item>
<item>
<layer-list>
<item android:left="0dp" android:top="0dp">
<shape>
<solid android:color="#99080d" />
<corners android:radius="3dip"/>
</shape>
</item>
<item android:bottom="3dp" android:right="2dp">
<shape>
<solid android:color="#a5040d" />
<corners android:radius="3dip"/>
</shape>
</item>
</layer-list>
</item>

Categories

Resources