I am using Action Bar Compat so that my action bar with navigation drawer was backward compatible down to API level 9 and I want to change the background of the action bar.
I copied the code from Android Developers:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- the theme applied to the application or activity -->
<style name="CustomActionBarTheme"
parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:actionBarStyle">#style/MyActionBar</item>
<!-- Support library compatibility -->
<item name="actionBarStyle">#style/MyActionBar</item>
</style>
<!-- ActionBar styles -->
<style name="MyActionBar"
parent="#style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">#drawable/actionbar_background</item>
<!-- Support library compatibility -->
<item name="background">#drawable/actionbar_background</item>
</style>
</resources>
And here comes the problem.
When I put an image drawable or a color as the background, it works fine. However I want to define the background as a gradient shape, so my actionbar_background looks like:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<gradient
android:startColor="#color/ac_bg_start"
android:endColor="#color/ac_bg_end"
android:type="linear"/>
<size
android:width="1dp"
android:height="48dp"/>
</shape>
I want it to be repeated in horizontal way but even this results in error, in fact, very interesting error. Test device and even the emulator gets restarted when I try to run the app. I was able to catch DeadObjectException before restarting.
How should the background drawable look like?
I am currently working on the same task.
Here is my action_bar_bg.xml file in which I define the gradient for my action bar.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:centerColor="#color/turquoise_action_bar"
android:endColor="#color/dark_turquoise"
android:startColor="#color/dark_turquoise" />
</shape>
DeadObjectException
android:shape="line" can't be used if there is a gradient inside. I tested it; my Samsung Galaxy Note 10.1 N8000 restarted, and there was a DeadObjectException.
The linear type of gradient pattern is the default value. So you don't have to declare it explicitly.
Here is my styles.xml in the values folder.
<resources>
<!-- Base application theme. -->
<style name="AppThemeBase" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:actionBarStyle">#style/PeopleCanAct</item>
<!-- Support library compatibility -->
<item name="actionBarStyle">#style/MyActionBar</item>
</style>
<style name="AppTheme" parent="AppThemeBase">
<!-- All the customizations that are NOT specific to a particular API level can go here -->
</style>
<!-- ActionBar styles -->
<style name="MyActionBar" parent="#style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">#drawable/action_bar_bg</item>
<!-- Support library compatibility -->
<item name="background">#drawable/action_bar_bg</item>
</style>
</resources>
Gradient Drawable
Another approach, without modifying styles.xml:
Here is our example GradientDrawable in res/drawable/ab_gradient.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:useLevel="false" >
<gradient
android:angle="90"
android:startColor="#000000"
android:endColor="#FFFFFF"
android:type="linear" />
</shape>
You can set it to action bar in your Activity's onCreate():
ActionBar actionBar = getActionBar();
actionBar.setBackgroundDrawable(getResources().getDrawable(R.drawable.action_bar_gradient_shape));
If you use support v7 library (your case):
// make sure to import android.support.v7.app.ActionBar
ActionBar actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(getResources().getDrawable(R.drawable.action_bar_gradient_shape));
Or if you use ActionBarSherlock:
// make sure to import com.actionbarsherlock.app.ActionBar
ActionBar actionBar = getSherlock().getActionBar();
actionBar.setBackgroundDrawable(getResources().getDrawable(R.drawable.action_bar_gradient_shape));
This is an example for the action bar xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="180"
android:endColor="#BF797777"
android:startColor="#A4231E35"
android:type="linear" />
</shape>
Instead of using android:shape="line" , in order to avoid DeadObjectException , you can set the android:angle to 180 or 0 - the effect will be the same, that is a horizontal line gradient.
I also use that sample code from Android Developer and use the gradient XML as like yours.
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
I found the different of this file between yours and mine is android:shape="line" / android:shape="rectangle".
So I try to change my rectangle to line. My app also occurs the same exception and the OS is restarted. Maybe the shape is the key point.
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
I would like to know, if it is possible to make my ActionBar have rounded edges, more specifically only the top ones (top-left, top-right). I did some searching, but most of the methods are outdated and did not work for me. I am using AppCompat support library v22.1.1.
I have made an image of what I am trying to achieve, but my reputation is too low to upload images so I tried to describe as best as I could with words. If I have missed out any relevant information, let me know.
Yes, it is possible by using a shape drawable.
First create actionbar_foreground.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#2C5AA9"/>
<corners
android:radius="0.1dp"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp"/>
</shape>
And then the background for the ActionBar. This color will be seen where the edges are rounded. I had trouble since I was using a light theme, where the decor view is white in color, so I made this "hack"
actionbar_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF000000"/>
</shape>
And now you just layer them (put one over the other). Bottom layer is the background. This is what I called actionbar_layer_list.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/actionbar_background"/>
<item android:drawable="#drawable/actionbar_foreground"/>
</layer-list>
And now just define a style for your app in the styles.xml
<!-- Base application theme. -->
<style name="AppTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
<style name="CustomActionBarTheme" parent="#style/AppTheme">
<item name="actionBarStyle">#style/CustomActionBar</item>
</style>
<!-- ActionBar styles -->
<style name="CustomActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="background">#drawable/actionbar_layer_list</item>
<item name="titleTextStyle">#style/CustomActionBarTextStyle</item>
</style>
And apply it in the AndroidManifest.xml
And it looks something like this
I'd like to change the menu divider left right margin
The original screenshot is like this
But I want to change to this
Currently, my style.xml is
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:dropDownListViewStyle">#style/PopupMenuListView</item>
</style>
<!-- Change Overflow Menu ListView Divider Property -->
<style name="PopupMenuListView" parent="#android:style/Widget.Holo.ListView.DropDown">
<item name="android:divider">#color/black</item>
<item name="android:dividerHeight">1px</item>
<!-- I put this line dividerPadding, but it doesn't work-->
<item name="android:dividerPadding">10px</item>
</style>
Any suggestion?
Thanks.
Eric
I found Sukhwant Singh Grewal's answer useful (hence upvoted) but a bit concise. Here's a more fully spelled-out solution.
In styles.xml I added the line:
<item name="android:listDivider">#drawable/divider</item>
Then I added the following divider.xml file under res/drawable:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#drawable/divider_line"
android:left="16dp"
android:right="16dp"/>
</layer-list>
Lastly, I added the following divider_line.xml file under res/drawable:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#color/pink_dark"/>
<corners
android:radius="3dp"/>
</shape>
This seemed to work for me.
under res/drawable
add divider.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:left="60dp"
android:right="10dp" android:drawable="#drawable/divider">
</item>
</layer-list>
in android:drawable="#drawable/divider_image"you can use any color like android:drawable="#color/black". Then take it as background of your divider and give height.
I have been working on updating my apps to Material Design.
I have an app that uses tabs. For some reason whenever I use android:popupBackground to set the drop down menu color it freaks out.
I set up a default project with tabs and used the following theme and the same thing happened. Has anyone one else had this problem? My app is open source and so all the code is available here GitHub
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="actionDropDownStyle">#style/Dropdown</item>
</style>
<style name="Dropdown" parent="Widget.AppCompat.Light.Spinner.DropDown.ActionBar">
<item name="android:popupBackground">#000</item>
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
</style>
</resources>
I had faced a similar issue with spinner. As #alanv mentioned use shape as background instead of colour will solve the problem.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="#000000" />
</shape>
UPDATE It is resolved in latest AppCompat.
I'm trying to have a style with a background image in the top right of the screen. I have this working with
my_theme_background.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="#color/myThemeBackgroundColor" />
</shape>
</item>
<item android:top="70dp">
<bitmap android:src="#drawable/bg_my_theme"
android:gravity="top|right" />
</item>
</layer-list>
Style
<style name="MyTheme" parent="AppBaseTheme">
<item name="android:windowBackground">#drawable/my_theme_background</item>
</style>
I have to use that android:top="70dp" to keep the image under the action bar. But the action bar changes height on rotation. How do I keep the image under the action bar in the xml without explicitly setting a top value?
I believe you can retreive its height via the attribute android.R.attr.actionBarSize. For instance for Honeycomb and later:
android:top="?android:attr/actionBarSize"
Or, according to Jake Wharton, for ActionBarSherlock compatibility:
android:top="?attr/actionBarSize"