I have a Button in my layout whose background and textcolor are defined as selectors. When unpressed the button has a background color and a textcolor and when pressed another color and another text color - e.g. white background with black text -> black background with white text.
At a certain point in my code I need to replace the background/text color with a third set of colors and then go back to the original selector defined in the xml. However, after going back the text no longer appears and instead I get just a solid colored button.
<Button
android:id="#+id/somebutton"
android:layout_width="80"
android:layout_height="80"
android:textColor="#color/sometext_selector"
android:background="#drawable/somebackground_selector"
android:gravity="center"
android:text="#string/sometext"
android:textSize="15sp"
/>
At this point everything is fine, but when I do this:
someButton.setBackgroundDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.backgroundRed, null));
someButton.setTextColor(getResources().getColor(android.R.color.holo_red_light));
and then afterwards this:
someButton.setBackgroundDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.originalBackgroundSelectorDefinedInXml, null));
someButton.setTextColor(getResources().getColor(R.color.originalTextSelectorDefinedInXml));
is when the problems begin.
Here are the xmls for my selectors - apologies for pseudocode, just imagine appropriate hex values:
First - the background:
<item android:drawable="#drawable/color_purple_full" android:state_selected="true"/>
<item android:drawable="#drawable/color_purple_full" android:state_pressed="true"/>
<item android:drawable="#drawable/color_purple_full" android:state_focused="true"/>
<item android:drawable="#drawable/color_purple_outline"/>
color_purple_outline:
android:shape="oval">
<stroke android:width="2dp" android:color="#somepurplehexa" />
<size android:width="80dp" android:height="80dp"/> </shape>
color_purple_full:
android:shape="oval">
<solid android:color="#somepurplehexa"/>
<size android:width="80dp" android:height="80dp" /> </shape>
for text:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#android:color/black" android:state_selected="true"/>
<item android:color="#android:color/black" android:state_pressed="true"/>
<item android:color="#android:color/black" android:state_focused="true"/>
<item android:color="#color/green"/>
What I'm seeing is the correct background in the unpressed state but in the pressed state I'm just getting a solid color with no text on it at all. I'd be grateful for any ideas as to why this is happening and why in the original xml it works fine but only stops working after changing it programmatically?
SOLVED:
turns out the problem was here:
someButton.setTextColor(getResources().getColor(R.color.originalTextSelectorDefinedInXml));
should have been
someButton.setTextColor(getResources().getColorStateList(R.color.originalTextSelectorDefinedInXml));
Related
Hi so I am little confused and wondering if anyone could point me in the right direction.
Go and use Google Play Store on Lollipop and pre-lollipop
You will see on lollipop that selectable views have the ripple effect.
On pre-lollipo, you get this highlight effect.
How is this done?
At the moment in my app, I have a drawable-v21 directory that contains this selector
It basically does the ripple on top of my background
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:id="#android:id/mask" android:drawable="#android:color/white"/>
<item android:drawable="#color/colorAccentWith92PercentOpacity"/>
</ripple>
However, other answers say to use
android:background="?attr/selectableItemBackground"
To get the highlight effect on pre-lollipop but this overrides my background. How could i set this on top of my current background?
Also do i have to create a ripple drawable (in drawble-v21) for every kind of button in my app? How would I do this for recycler view items?
What makes this question unique
I do not want ripple for pre-lollipop I am asking how devs efficiently make their button do ripple on lollipop and a hight light effect on pre
Option 1
Define colorControlHighlight in your theme and as long you're using default appcompat-v7 buttons the highlight color should work out-of-the-box.
Option 2
This is an example of how I backported Material button style with a bit of crossfade animation and shadows without using external libraries. May it help you on your way.
Provided the button will be white text over dark background (#color/control_normal) with light highlight:
values/themes.xml
Here I'll override default button style for the whole theme:
<style name="AppTheme" parent="Base.AppTheme">
<item name="buttonStyle">#style/Widget.AppTheme.Button</item>
</style>
values/integers.xml
<!-- Some numbers pulled from material design. -->
<integer name="button_pressed_animation_duration">100</integer>
<integer name="button_pressed_animation_delay">100</integer>
values-v21/styles.xml
Button style for Lollipop which understands theme overlays and uses ripple by default. Let's just have it color the ripple with appropriate paint:
<style name="Widget.AppTheme.Button" parent="Widget.AppCompat.Button">
<!-- On Lollipop you can define theme via style. -->
<item name="android:theme">#style/ThemeOverlay.AppTheme.Button</item>
</style>
<style name="ThemeOverlay.AppTheme.Button" parent="ThemeOverlay.AppCompat.Dark">
<!-- The magic is done here. -->
<item name="colorButtonNormal">#color/control_normal</item>
</style>
values/styles.xml
Before Lollipop it gets tricky.
<style name="Widget.AppTheme.Button" parent="Widget.AppCompat.Button">
<item name="android:background">#drawable/button_normal_background</item>
</style>
drawable/button_normal_background.xml
Thi is the composite drawable of the whole button.
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="#dimen/abc_button_inset_horizontal_material"
android:insetTop="#dimen/abc_button_inset_vertical_material"
android:insetRight="#dimen/abc_button_inset_horizontal_material"
android:insetBottom="#dimen/abc_button_inset_vertical_material">
<layer-list>
<!-- Shadow. -->
<item
android:drawable="#drawable/button_shadow"
android:top="-0dp"
android:bottom="-1dp"
android:left="-0dp"
android:right="-0dp"/>
<item
android:drawable="#drawable/button_shadow_pressable"
android:top="-0dp"
android:bottom="-3dp"
android:left="-1dp"
android:right="-1dp"/>
<!-- Background. -->
<item android:drawable="#drawable/button_shape_normal"/>
<!-- Highlight. -->
<item>
<selector
android:enterFadeDuration="#integer/button_pressed_animation_duration"
android:exitFadeDuration="#integer/button_pressed_animation_duration">
<item
android:drawable="#drawable/button_shape_highlight"
android:state_focused="true"
android:state_enabled="true"/>
<item
android:drawable="#drawable/button_shape_highlight"
android:state_pressed="true"
android:state_enabled="true"/>
<item
android:drawable="#drawable/button_shape_highlight"
android:state_selected="true"
android:state_enabled="true"/>
<item android:drawable="#android:color/transparent"/>
</selector>
</item>
<!-- Inner padding. -->
<item android:drawable="#drawable/button_padding"/>
</layer-list>
</inset>
drawable/button_shadow.xml
This is the shadow when not pressed.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="3dp"
android:bottomRightRadius="3dp"
android:topLeftRadius="2dp"
android:topRightRadius="2dp"/>
<solid android:color="#2000"/>
</shape>
drawable/button_shadow_pressable.xml
This is the extended shadow in pressed state. The result effect will look crude when you look up close but it's good enough from distance.
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="UnusedAttribute"
android:enterFadeDuration="#integer/button_pressed_animation_duration"
android:exitFadeDuration="#integer/button_pressed_animation_duration">
<item
android:state_pressed="true"
android:state_enabled="true">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="3dp"
android:topRightRadius="3dp"/>
<solid android:color="#20000000"/>
</shape>
</item>
<item android:drawable="#android:color/transparent"/>
</selector>
drawable/button_shape_normal.xml
This is the main button shape.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="#dimen/abc_control_corner_material"/>
<solid android:color="#color/control_normal"/>
</shape>
drawable/button_padding.xml
Just additional padding to be absolutely consistent with the Material button.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#android:color/transparent"/>
<padding
android:left="#dimen/abc_button_padding_horizontal_material"
android:top="#dimen/abc_button_padding_vertical_material"
android:right="#dimen/abc_button_padding_horizontal_material"
android:bottom="#dimen/abc_button_padding_vertical_material"/>
</shape>
drawable/button_shape_highlight.xml
This is the highlight button shape drawn over normal button shape.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="#dimen/abc_control_corner_material"/>
<solid android:color="#color/control_highlight"/>
</shape>
#color/control_highlight can point to
#color/ripple_material_dark - translucent white, use over dark background
#color/ripple_material_light - translucent black, use over light background
Any other color you define.
You can set a background of your views in this way:
android:background="#drawable/touch_selector"
Create a version without ripple for pre lollipop:
drawable/touch_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- State when a row is being pressed, but hasn't yet been activated (finger down) -->
<item android:state_pressed="true"
android:drawable="#color/grey"
/>
<!-- For ListView in SINGLE_CHOICE_MODE, it flags the active row -->
<item android:state_activated="true"
android:drawable="#color/light_green" />
<!-- Default, "just hangin' out" state. -->
<item android:drawable="#android:color/transparent" />
</selector>
Now do the same for lollipop and above,
but with ripple effect:
crete drawable-v21/touch_selector.xml
It will look like:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- State when a row is being pressed, but hasn't yet been activated (finger down) -->
<item android:state_pressed="true">
<ripple android:color="#color/grey" />
</item>
<!-- For ListView, when the view is "activated". In SINGLE_CHOICE_MODE, it flags the active row -->
<item android:state_activated="true"
android:drawable="#color/light_green" />
<!-- Default, "just hangin' out" state. -->
<item android:drawable="#android:color/transparent" />
</selector>
That's it.
Now you are having ripple effect at lollipop and above devices and highlight at pre lollipop.
Edit:
In case of using in a ListView - use created above as a background of ListView item
Can I change the line color on EditText. When is active it has some greenish color.
Is it possible to change only the color of line when is active, and how can I do this...?
You need to set background source for an edit text.
Generate it http://android-holo-colors.com/
Than you can apply generated drawable as background like android:background="#drawable/my_theme_edit_text" for the custom EditText. Or you can set that background in your app theme - you will find example in .zip file from that site
add to your themes.xml this line:
<item name="colorAccent">#color/black</item>
this sets the default color for colorControlActivated which is used to tint widgets
Here you are:
editText.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
You can set background of edittext to a rectangle with minus padding on left, right and top to achieve this.
Here is the xml example for setting different line colors for focused and not focused edittext, just set it as background of edittext.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="-2dp"
android:left="-2dp"
android:right="-2dp"
android:bottom="2dp">
<selector >
<item android:state_enabled="true"
android:state_focused="true">
<shape
android:shape="rectangle">
<stroke
android:width="2dp"
android:color="#6A9A3A"/>
</shape>
</item>
<item android:state_enabled="true">
<shape
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#000000"/>
</shape>
</item>
</selector>
</item>
</layer-list>
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="#drawable/text"
android:ems="10"
android:textColorHint="#fefefe"
android:hint="#string/text1"
android:textColor="#fefefe"
android:inputType="textEmailAddress"
android:layout_marginTop="10dp"
/>
Use the below code in your res/drawable/text.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:top="24.0dp">
<shape >
<solid android:color="#fefefe" />
</shape>
</item>
</layer-list>
you can set android:backgroundTint="#color/blue" to change the color of the Edittext bottom line
I had the same problem
solved it by changing the color of the backgroundTint as follows -
android:backgroundTint="#color/light_color"
You can use the android:background = "#color/black" for the api 21 or above 21 (This will apply for lollypop device or above versions) and for below versions you should use the style to the edittext.
If your using TextInputLayouts for EditText, we should change the following properties.
<item name="colorControlNormal">#c5c5c5</item>
<item name="colorControlActivated">#color/your color</item>
<item name="colorControlHighlight">#color/your color</item>
By default colour is colorAccent.
I want to make a weekly calendar, where every day is a custom checkbox with objective to look like the image bellow:
(http://i.imgur.com/WjIKCd0.png)
When the user clicks on a day (Monday in this case), the "background" and "button" checkbox changes as well the text color...
I made the drawables and it seems to work fine... check bellow the code:
Checkbox layout:
<CheckBox
android:id="#+id/selectMonday"
android:layout_width="40dp"
android:layout_height="40dp"
android:button="#drawable/ic_none"
style="#style/CheckBoxBackgroundView"
android:onClick="selectDay"
android:text="#string/monday_letter"
android:gravity="center"
android:checked="true"/>
(the drawable "ic_none", is simple a 135x135 "transparent" image with nothing in it...)
Style (CheckBoxBackgroundView):
<style name="CheckBoxBackgroundView">
<item name="android:background">#drawable/background_day_week_picker_box_selector</item>
<item name="android:textColor">#color/text_color_day_week_picker_box_selector</item>
<item name="android:textSize">#dimen/text_spinner_text</item>
<item name="android:textStyle">bold</item>
</style>
Background Selector (background_day_week_picker_box_selector):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false"
android:drawable="#drawable/background_day_of_week_picker_unselected" />
<item android:state_checked="true"
android:drawable="#drawable/background_day_of_week_picker_selected" />
</selector>
Background selected (background_day_of_week_picker_selected):
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- view background color -->
<solid
android:color="#color/red_color" >
</solid>
<!-- view border color and width -->
<stroke
android:width="3dp"
android:color="#color/transparent">
</stroke>
<!-- Here is the corner radius -->
<corners
android:radius="10dp" >
</corners>
</shape>
and finally the color selector (text_color_day_week_picker_box_selector):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false"
android:color="#color/red_color"></item>
<item android:state_checked="true"
android:color="#color/white"></item>
</selector>
I tried this in several devices... in some, it appears like it suppose to, in others the text disappears and it looks like this:
(http://i.imgur.com/Jy9FrPS.png)
probably is coincidence, but all the devices that worked are below 5 inches...
is there anything wrong with my code that I'm not seeing? anyone have any suggestions?
Thanks in advance
The problem is that the 135x135 button drawable is pushing the text out of the bounds of your CheckBox's width. Instead of using a drawable, you can just set android:button="#color/transparent".
I have the following definition of an android style and selector applied to ListView, however I see no effect of gray gradient applied when I click on it. On click it immediately displays blue gradient.
As author of this example has written:
We want to apply this to our list selector. Instead of always showing
the same gradient, we want the gradient to change its start color from
grey to a light blue whenever a list item is pressed. Because we now
have two different list selectors—one for default state one for
pressed state—we need to keep them in separate files.
Can someone explain how it should be displayed properly ? Or I'm missing something ?
More general, what exactly I should expect to see on display screen ? Something like fluent transition from gray gradient to blue gradient on list item click ?
Update: this is how author 'sees' it, but when I click on item it looks only like on right side of picture. May I assume that author wants to see all items in list to be gray by default ? Or this state is not applicable to list view items ?
list_item_default.xml -> GRAY GRADIENT
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:angle="0"
android:endColor="#FFFF"
android:startColor="#AFFF" />
<stroke
android:width="1dip"
android:color="#CCC" />
<corners android:radius="5px" />
</shape>
list_item_pressed.xml -> BLUE GRADIENT
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:angle="0"
android:endColor="#FFFF"
android:startColor="#AA66CCFF" />
<stroke
android:width="1dip"
android:color="#CCC" />
<corners android:radius="5px" />
</shape>
list_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/list_item_default" android:state_pressed="false"/>
<item android:drawable="#drawable/list_item_pressed" android:state_pressed="true"/>
</selector>
styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyMoviesTheme" parent="#android:style/Theme.Black">
<item name="android:listViewStyle">#style/MyMoviesListView</item>
<item name="android:windowBackground">#drawable/film_bg</item>
</style>
<style name="MyMoviesTextAppearance" parent="#android:style/TextAppearance">
<!--<item name="android:textStyle">bold</item>-->
</style>
<style name="MyMoviesListView" parent="#android:Widget.ListView">
<item name="android:background">#color/list_background</item>
<item name="android:listSelector">#drawable/list_selector</item>
<item name="android:cacheColorHint">#android:color/transparent</item>
<item name="android:fastScrollEnabled">true</item>
<item name="android:footerDividersEnabled">false</item>
</style>
</resources>
Try adding a sentence:
<item
android:state_enabled="true"
android:drawable="#drawable/list_item_default"/>
<item
android:state_enabled="true"
android:drawable="#drawable/list_item_pressed"
android:state_pressed="true"/>
I have a dashboard with icons and text like in the picture below.
What I want is a round-cornered filled background behind the 'My status' text. I drew on the picture what I want, but it needs to be filled, not only bordered like here (it's just for clarity that I drew it like that on the picture).
Right now this button is made through a style:
<style name="DashboardButton">
<item name="android:layout_gravity">center_vertical</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:drawablePadding">2dp</item>
<item name="android:textSize">14dp</item>
<item name="android:textColor">#877871</item>
<item name="android:background">#null</item>
</style>
How can I adapt this style to acheive it?
Can I also set the hover and active states via a style?
For the background to the button's text you either try to do this with a custom background graphic, but I think it would be easier to split your "button" into two parts and render the icon part as an ImageButton and for the label part as a normal button with a custom ShapeDrawable for the background, e.g. like so:
<shape>
<solid android:color="#0000FF" />
<stroke
android:width="2dp"
android:color="#FFFFFF" />
<corners
android:radius="8dp" />
<padding
android:left="8dp"
android:top="8dp"
android:right="8dp"
android:bottom="8dp" />
</shape>
For setting hover and active states you can use Android's StateListDrawable.