Asiat
Asiat

Reputation: 401

android selectableItemBackground selection

i want to change background of my view when the state is "activated" and i want to preserve the effects(ripple) of ?attr:selectableItemBackground. Is it possible to extend or combine selector of ?attr:selectableItemBackground?

Upvotes: 21

Views: 7726

Answers (5)

Mickäel A.
Mickäel A.

Reputation: 9357

For those who only care about API >= 21 now in 2020, here's a simpler solution :

<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?colorControlHighlight">
    <!-- 🡡 the ripple's color (1) -->

    <!-- 🡣 no `id` so our <shape> will be drawn and not just used as mask -->
    <item>
        <shape>
            <corners android:radius="9dp" />
            <solid android:color="@color/white" />
        </shape>
    </item>

</ripple>

(1) If you don't override colorControlHighlight in your theme, the ripple's color will be Android's default. If you do override it in your theme but want to use Android's default for a specific case use ?android:colorControlHighlight instead.

Upvotes: 3

Gene S
Gene S

Reputation: 553

I solved this problem by swapping the background drawables at runtime. This code runs in onBindViewHolder in RecyclerView.Adapter<MyViewHolder>:

if (selected) {
    itemView.setBackgroundResource(R.drawable.selected_background);
} else {            
    TypedArray typedArray = context.obtainStyledAttributes(
          new int[]{android.R.attr.selectableItemBackground});
    itemView.setBackgroundResource(typedArray.getResourceId(0, 0));
    typedArray.recycle();
}

The R.drawable.selected_background refers to the background of a selected item:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorAccentLight" android:state_activated="true" />
    <item android:drawable="@android:color/transparent" />
</selector>

Another solution is to have two identical item types except for different backgrounds but that seems to be an overkill.

Upvotes: 0

Alex Semeniuk
Alex Semeniuk

Reputation: 1875

Unfortunately, the only way I found is to have additional view in your layour that will emulate the selected state. Like so (works on pre-Lollipop as well):

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="?attr/listPreferredItemHeight"
    android:background="?attr/selectableItemBackground">

    <View
        android:id="@+id/item_selected"
        android:visibility="gone"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="?attr/colorControlHighlight"/>

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/item_title"
        android:layout_gravity="center_vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:textAppearance="?attr/textAppearanceListItem"/>

</FrameLayout>

Then in your adapter you set visibility of item_selected to either View.VISIBLE or View.GONE, based on the need to make this particular item selected.

P.S. Obviously, this solution uses AppCompat support library, so in order to use it the following line should be added to build.gradle file:

implementation 'com.android.support:appcompat-v7:28.0.0'

Upvotes: 0

Nit
Nit

Reputation: 1145

You can use a LayerDrawable in order to draw the ripple effect drawable (?attr:selectableItemBackground) over your activated state color.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <selector>
            <item android:state_activated="true">
                <color android:color="?attr/colorPrimary"/>
            </item>
            <item>
                <color android:color="@android:color/transparent"/>
            </item>
        </selector>
    </item>
    <item android:drawable="?attr/selectableItemBackground"/>
</layer-list>

Edit: As it's not possible to use theme attributes in an XML drawable before API 21, it seems to be better to put the ripple effect drawable as a foreground drawable, and the activated color selector drawable as a background drawable.

<View
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/yourView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:foreground="?attr/selectableItemBackground"
    android:background="@drawable/activated_color_selector">

With res/drawable/activated_color_selector.xml containing:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_activated="true">
        <!-- Can't use the ?attr/colorPrimary before API 21 -->
        <color android:color="@color/primaryColor"/>
    </item>
    <item>
        <color android:color="@android:color/transparent"/>
    </item>
</selector>

Upvotes: 20

Rohit
Rohit

Reputation: 49

To change ripple color throughout the app you can ad this in your app theme

<item name="colorControlHighlight">@color/ripple</item>

Upvotes: 0

Related Questions