Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make style="?attr/actionButtonStyle" workable for rectangle toolbar button

Tags:

android

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.

actionbar_custom_view_done_discard.xml

<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>

actionbar_done_button.xml

<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>

StockAlertFragmentActivity.java

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.

enter image description here

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.

toolbar_with_save_discard.xml

<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>

toolbar_save_button.xml

<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>

enter image description here

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.


like image 281
Cheok Yan Cheng Avatar asked Apr 23 '16 07:04

Cheok Yan Cheng


1 Answers

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.

like image 90
Vikram Avatar answered Sep 20 '22 13:09

Vikram