Android Ripple Effect + Elevation on non-Button Views
Asked Answered
M

2

9

I am trying to add touch feedback to a LinearLayout that is similar to a regular Button's feedback in API level 21, much like in this example, and have been so far unsuccessful.

I have defined a standard ripple drawable like this:

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">

<item android:id="@android:id/mask">
    <shape android:shape="rectangle">
        <solid android:color="?android:colorAccent" />
    </shape>
</item>

and used the StateListAnimator that Google provides here:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:state_pressed="true">
    <objectAnimator
        android:duration="@android:integer/config_shortAnimTime"
        android:propertyName="translationZ"
        android:valueTo="@dimen/touch_raise"
        android:valueType="floatType" />
</item>
<item>
    <objectAnimator
        android:duration="@android:integer/config_shortAnimTime"
        android:propertyName="translationZ"
        android:valueTo="0dp"
        android:valueType="floatType" />
</item>

After defining the animator and ripple drawable, i've added them to my LinearLayout like so:

<LinearLayout
    android:id="@+id/linearLayout"        
    android:clickable="true"
    android:focusable="true"
    android:orientation="horizontal"
    android:background="@drawable/ripple"
    android:stateListAnimator="@anim/touch_elevation">

The idea is to use this LinearLayout as a button, as it is much simpler for me to insert various types of text and handle ImageView positioning inside it (as opposed to button drawables).

Adding the ripple effect or the animation separately works, so long as the background of the view has no transparency as per this question.

I am not sure if this is an issue related to the above mentioned question, but seeing as the standard button manages to employ both ripple and elevation animation feedback, I figure that achieving this effect is possible on other views as well.

Any insight into this problem would be greatly appreciated.

Martens answered 28/1, 2015 at 12:32 Comment(7)
If you are expecting the ripple effect to be applied when the user taps on your LinearLayout, you need to use an appropriate StateListDrawable, not directly referencing your <ripple>.Hatteras
Your existing background says "show a ripple immediately". That seems like a curious choice. The background of a Button is a StateListDrawable, to use different images for normal, pressed, disabled, focused, etc. You would need to do the same thing.Hatteras
I think i get you but oddly enough, as I mentioned in my question, if I only specify the ripple as the background, it works as intended.Martens
What effect happens with both?Shanon
No effect whatsoeverMartens
RippleDrawable handles both pressed and focus state. You don't need to use a StateListDrawable. What do you mean by, "the background of the view has no transparency"? Aren't you using the ripple as the background?Quittance
Also, the mask is just used as an alpha channel. You can use <color android:color="@color/white" /> rather than a shape drawable.Quittance
B
3

Use ForegroundLinearLayout. It allows to put ripple or any another drawable in foreground of view. The same way you can create ForegroundRelativeLayout etc. (just make this class extend from RelativeLayout).

Here is example with your stateListAnimator and ripple drawable:

<your.package.ForegroundLinearLayout
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:foreground="@drawable/bg_ripple"
    android:background="#fff"
    android:clickable="true"
    android:stateListAnimator="@animator/animator_elevation">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello world!"/>

</your.package.ForegroundLinearLayout>

Result:

enter image description here

EDIT: ForegroundLinearLayout exists in support design library. So you can just use android.support.design.internal.ForegroundLinearLayout

Bobwhite answered 22/9, 2016 at 8:52 Comment(0)
S
1

Both effects work togheter without android:id="@android:id/mask"attribute in the ripple's item element (maybe this attribute adds some transparency ).

Shanon answered 29/1, 2015 at 13:55 Comment(2)
Indeed both the effects work together without the mask. It is clearly that same transparency issue then. I am sorry but i can't use your solution, since i was looking to apply both effects on any item. Using this solution on a CardView for example (where the ripple must be the foreground), renders the entire content of the view invisible.Martens
I never thought android:id/mask could be the cause of elevation not showing for my <ripple> drawables!!!Craniology

© 2022 - 2024 — McMap. All rights reserved.