Reputation: 401
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
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 overridecolorControlHighlight
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
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
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
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
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