ywwynm
ywwynm

Reputation: 11695

How can I modify ripple color when using ?attr/selectableItemBackground as background?

I've seen some SO questions and they gave some possible methods to achieve what I want. For example:

  1. Use colorControlHighlight attribute in styles.xml.

    Here is my styles-v21.xml:

    <style name="SelectableItemBackground">
        <item name="android:colorControlHighlight">#5677FC</item>
        <item name="android:background">?attr/selectableItemBackground</item>
    </style>
    

    And my widget:

    <TextView
        android:id="@+id/tv_take_photo_as_bt"
        android:layout_width="280dp"
        android:layout_height="48dp"
        android:text="@string/act_take_photo"
        style="@style/SelectableItemBackground"/>
    

    And it doesn't work. I also tried to add parent="Theme.AppCompat to "SelectableItemBackground" style, or change to colorControlHighlight(no android: prefix)", or change to ?android:attr/selectableItemBackground, neither is useful.

  2. Use backgroundTint attribute in layout.

    So I add android:backgroundTint="#5677FC" to my TextView. Still useless. Then I tried to change android:backgroundTintMode to src_in and src_atop, and they never make a difference.

So, how can I change ripple color when I use ?attr/selectableItemBackground as background. I only focus on Lollipop and above. Thank you in advance!

Upvotes: 132

Views: 84513

Answers (10)

android developer
android developer

Reputation: 116332

If you want to do it programmatically, this solution I've worked on should work at least for most of the cases:

fun View.setBackgroundTintColor(@ColorInt color: Int) {
    val background = background
    if (background is RippleDrawable) {
        val newBackground = background.mutate() as RippleDrawable
        if (color != 0)
            newBackground.setColor(ColorStateList.valueOf(color))
        this.background = newBackground
    } else {
        if (color == 0)
            ViewCompat.setBackgroundTintList(this, null)
        else
            ViewCompat.setBackgroundTintList(this, ColorStateList.valueOf(color))
    }
}

Usage:

yourView.setBackgroundTintColor(0xffff0000.toInt())

And to reset to normal:

yourView.setBackgroundTintColor(0)

As you can see, you should know that using it might make the View have a new background, sadly.

Upvotes: 0

SerjantArbuz
SerjantArbuz

Reputation: 1234

In your xml set background:

<View
    android:id="@+id/click_view"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:layout_gravity="center"
    android:background="?attr/selectableItemBackgroundBorderless" <!-- Set ripple this way -->
    android:contentDescription="@null" />

And in your code change color of it:

// Take borderless ripple
val ripple = clickView.background as? RippleDrawable 

// Change color here
ripple?.setColor(ColorStateList.valueOf(Color.RED))

Don't know how it works with Lollipop.

Upvotes: 0

Prajwal Waingankar
Prajwal Waingankar

Reputation: 2710

Use the below steps:

1. Make changes to button view in your layout.xml
2. Add new styles in styles.xml

your_layout.xml

<Button
                        android:id="@+id/setup_submit_button"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="16dp"
                        android:text="@string/action_sign_in"
                        android:textStyle="bold"
                        android:background="@color/colorPrimary"
                        android:textColor="@color/white"
                        style="@style/SelectableItemBackground"
                        android:foreground="?android:attr/selectableItemBackground"/>

-The style attribute calls the style that we created.

-Foreground attribute calls the andorid's default selectable attribute.

styles.xml

 <style name="SelectableItemTheme">
        <item name="colorControlHighlight">@color/white</item>
    </style>


    <style name="SelectableItemBackground">
        <item name="android:theme">@style/SelectableItemTheme</item>
        <item name="android:background">?attr/selectableItemBackground</item>
    </style>

Upvotes: 13

Omkar
Omkar

Reputation: 3100

In dark black theme(Or any other) app try to use like below first create ripple_effect.xml in drawable folder and add code like

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#f5f5f5">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5" />

        </shape>
    </item>

</ripple>

then set background to your Any view like Linear layout, Button, TextView etc.

 <TextView
                    android:id="@+id/tvApply"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@drawable/ripple_effect"
                    android:clickable="true"
                    android:text="APPLY"
                    android:textColor="#FFFFFF"
                    android:gravity="center"
                    android:textSize="@dimen/_8sdp"
                    android:padding="@dimen/_8sdp"
                    android:focusable="true" />

Upvotes: 0

Michael Winkler
Michael Winkler

Reputation: 141

This code works for me to create a ripple:

public static void setRippleDrawable(View view, int normalColor, int touchColor) {
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            RippleDrawable rippleDrawable = new RippleDrawable(ColorStateList.valueOf(touchColor), view.getBackground(), null);
            view.setBackground(rippleDrawable);
        } else {
            StateListDrawable stateListDrawable = new StateListDrawable();
            stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(touchColor));
            stateListDrawable.addState(new int[]{android.R.attr.state_focused}, new ColorDrawable(touchColor));
            stateListDrawable.addState(new int[]{}, new ColorDrawable(normalColor));
            view.setBackground(stateListDrawable);
            }
    } catch (Exception e) {
        Log.e(LOG_TAG, "" + e);
    }
}

I did not found any way to modify the selectableItemBackground attribute. That's why I did it like above.

Upvotes: 0

Mahdi Khansari
Mahdi Khansari

Reputation: 435

It's showing ripple effect with color on API +21, and simple gray background on press for API -21. Add this style:

<style name="AppTheme.MyRipple">
   <item name="colorControlHighlight">@color/your_color</item>
   <item name="android:background">?selectableItemBackgroundBorderless</item>
</style>

And set it to the view:

<Button
   ...
   android:theme="@style/AppTheme.MyRipple" />

Upvotes: 16

Kirill Karmazin
Kirill Karmazin

Reputation: 6736

Ripple effect on pre- and Lollipop+ devices

harrane and Liuting are right. The accepted answer is not the best way. Let me show in code how to change ripple color for pre-Lollipop versions and higher

  1. Your AppTheme should inherit from any AppCompat theme and contain colorControlHighlight attribute (without 'android:' prefix)

    <!-- Application theme. -->
    <style name="AppTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
    <item name="colorControlHighlight">#40ffffff</item>
    </style>
    
  2. Your view should contain clickable="true" (or should have a click listener set programmatically) and background should be "?attr/selectableItemBackgroundBorderless" or "?attr/selectableItemBackground" :

    <LinearLayout
    ...
    android:clickable="true"
    android:background="?attr/selectableItemBackgroundBorderless"/>
    

Note: that if your parent view has white background you won't see ripple effect since it's white. Change colorControlHighlight value for a different color

Also, if you want different ripple colors on different activities you can set personal theme for each activity in Manifest file, for example:

       <activity
        android:name="com.myapp.GalleryActivity"
        android:theme="@style/RedRippleTheme"
        />

Different ripple colors for different fragments in the same activity?

You can change attributes of Activity Theme for each fragment in runtime. Just overwrite them before fragment was inflated with your custom style and apply to a current Theme:

in values/styles.xml

    <style name="colorControlHighlight_blue">
       <item name="colorControlHighlight">@color/main_blue_alpha26</item>
    </style>

Then, in your fragment before inflation in onCreateView():

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       getContext().getTheme().applyStyle(R.style.colorControlHighlight_blue, true); //blue ripple color
       View view = inflater.inflate(R.layout.my_fragment_layout, container, false);
       return view;
    }

This style will work only for this fragment


Different ripple color for different Views? (Lollipop +)

You can change the ripple color for each view seperately using colorControlHighlight attribute, it doesn't work if you apply them to a view directly:

    <TextView
     ...
     colorControlHighlight="#40ffffff"/> <!-- DOESN'T WORK -->

you should apply it as a theme:

<TextView
  ...
  android:theme="@style/colorControlHighlight_blue"/>

P.S. Also, sometimes this approach helps if you have unknown issues with ripple and you can't figure it out. In my case, I used 3rd party sliding lib which messed up ripple effects for the entire layout and adding explicitly this theme to all clickable views worked out for me.

Upvotes: 68

Titto Jose
Titto Jose

Reputation: 72

Use the foreground attribute as selectableItemBackground and background attribute as the color you want.

android:foreground="?attr/selectableItemBackground"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:background="@color/white"

Upvotes: -1

harrane
harrane

Reputation: 969

The accepted answer is wrong.

The correct way to use is what Liuting mentioned in the comment. Use colorControlHighlight instead of android:colorControlHighlight for changing the default colorControlHighlight from AppCompat

* Please refer to http://android-developers.blogspot.co.uk/2014/10/appcompat-v21-material-design-for-pre.html in the Theming section *

Upvotes: 8

ywwynm
ywwynm

Reputation: 11695

Finally I find the solution: instead of using android:colorControlHighlight directly in theme SelectableItemBackground, I should write another style:

<style name="SelectableItemTheme">
    <item name="colorControlHighlight">@color/ripple_color</item>
</style>

Then:

<style name="SelectableItemBackground">
    <item name="android:theme">@style/SelectableItemTheme</item>
    <item name="android:background">?attr/selectableItemBackground</item>
</style>

Finally add style="@style/SelectableItemBackground" to View in layout.xml.

UPDATED ON 2016/8/26 After N's release, I found that sometimes we cannot use this method to set ripple color for some kind of View(for example, the CardView). Now I highly recommend developers using RippleDrawable, which can also be declared in xml. Here is an example:

I want to show a ripple effect when user touches/clicks a CardView above API21, and of course there should be another kind of feedback before Lollipop. So I should write:

<android.support.v7.widget.CardView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:foreground="@drawable/selectable_item_background"/>

and selectable_item_background in drawable folder:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="false" android:drawable="@android:color/transparent" />
    <item android:drawable="@color/color_clicked" />
</selector>

selectable_item_background in drawable-v21 folder:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ripple_black" />
</selector>

finally, the ripple_black in drawable(or drawable-v21) folder:

<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:color="@color/color_clicked"
    tools:ignore="NewApi" /> <!--you can remove this line if it's in v21 folder-->

That's it. For other views, maybe you should use android:background="@drawable/selectable_item_background". Don't forget to set an OnClickListener, OnTouchListener or something like those for them, otherwise ripple won't show.

Upvotes: 183

Related Questions