In our previous holo designed app (targetSdkVersion
21, with theme Theme.Sherlock.Light.DarkActionBar
), we are using system style attribute attr/actionButtonStyle
to define our custom action bar button style.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<include layout="@layout/actionbar_discard_button" />
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:background="?attr/actionBarCustomViewDividerColor" />
<include layout="@layout/actionbar_done_button" />
</LinearLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="?attr/actionButtonStyle"
android:id="@+id/actionbar_done"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView style="?attr/actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingRight="20dp"
android:drawableLeft="?attr/actionBarDoneIcon"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:text="@string/save" />
</FrameLayout>
public class StockAlertFragmentActivity extends SherlockFragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate a "Done/Discard" custom action bar view.
LayoutInflater inflater = (LayoutInflater) this.getSupportActionBar().getThemedContext()
.getSystemService(LAYOUT_INFLATER_SERVICE);
final View customActionBarView = inflater.inflate(
R.layout.actionbar_custom_view_done_discard, null);
The outcome is as following, when we tap on the SAVE button.
However, after migrating our app to material designed app (targetSdkVersion
23, theme Theme.AppCompat.Light.NoActionBar
), system attribute attr/actionButtonStyle
no longer work well with rectangle button.
Instead, it draws a round overlay on the top of rectangle button.
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:contentInsetLeft="0dp"
android:contentInsetStart="0dp"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
android:contentInsetRight="0dp"
android:contentInsetEnd="0dp"
app:contentInsetRight="0dp"
app:contentInsetEnd="0dp"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" >
<!-- android:elevation="4dp" is used due to http://www.google.com/design/spec/what-is-material/elevation-shadows.html#elevation-shadows-elevation-android- -->
<LinearLayout
android:id="@+id/buttons_linear_layout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:orientation="horizontal">
<include layout="@layout/toolbar_discard_button" />
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:background="?attr/toolbarCustomViewDividerColor" />
<include layout="@layout/toolbar_save_button" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="?attr/actionButtonStyle"
android:id="@+id/toolbar_save"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView style="?attr/actionBarTabTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingRight="20dp"
android:drawableLeft="?attr/toolbarDoneIcon"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:text="@string/save" />
</FrameLayout>
I like to have the overlay drawn on the entire rectangle SAVE button.
I think most probably I can solve this, by avoiding from using style="?attr/actionButtonStyle"
, and supplying my very own defined selector.
However, I prefer not to do so. I prefer to use system provided style, for less maintenance headache.
How can I make style="?attr/actionButtonStyle"
workable for rectangle toolbar button?
Or, Is there any other system style attribute, which will work well with rectangle toolbar button? At the same time, having ripple effect.
Attribute at play here is: actionButtonStyle
which you set on your wrapping FrameLayout
. On v23, it points to:
<style name="Widget.Material.ActionButton">
<item name="background">?attr/actionBarItemBackground</item>
<item name="paddingStart">12dp</item>
<item name="paddingEnd">12dp</item>
<item name="minWidth">@dimen/action_button_min_width_material</item>
<item name="minHeight">@dimen/action_button_min_height_material</item>
<item name="gravity">center</item>
<item name="scaleType">center</item>
<item name="maxLines">2</item>
</style>
The background
is set to actionBarItemBackground
which in turn points to this RippleDrawable
:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight"
android:radius="20dp" />
The radius value is what you don't want.
To fix this, override actionBarItemBackground
under your app's theme:
<style name="AppTheme" parent="....">
....
<item name="actionBarItemBackground">@drawable/custom_action_bar_item_bg</item>
<item name="android:actionBarItemBackground">@drawable/custom_action_bar_item_bg</item>
</style>
The drawable custom_action_bar_item_bg
would be defined as:
res/drawable/custom_action_bar_item_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<color android:color="#...."/>
</item>
<item>
<color android:color="@android:color/transparent"/>
</item>
</selector>
res/drawable-v21/custom_action_bar_item_bg.xml
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:id="@id/mask">
<color android:color="@android:color/white" />
</item>
</ripple>
The mask
is what will give you the rectangle in case of API version > 21.
The downside: all items that use actionBarItemBackground
will be affected (unless if that's okay). To fix this, you can create a separate theme to set on your FrameLayout
wrapper. For example, this is your app's main theme:
<style name="AppTheme" parent="....">
....
....
</style>
Create another theme that inherits from AppTheme
:
<style name="SelectiveActionBarButtonTheme" parent="AppTheme">
<item name="actionBarItemBackground">@drawable/custom_action_bar_item_bg</item>
<item name="android:actionBarItemBackground">@drawable/custom_action_bar_item_bg</item>
</style>
To use this, override android:theme
on your wrapper FrameLayout
:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="?attr/actionButtonStyle"
android:id="@+id/toolbar_save"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:theme="@style/SelectiveActionBarButtonTheme">
....
....
</FrameLayout>
And of course, the simplest approach would be to set FrameLayout's
android:background
to ?attr/selectableItemBackground
, and be done with it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With