1

I have a layout with a KenBurnsView and an ImageView over it (just a toggle button). When I click on the button a Ripple is generated but is drawn below the KenBurnsView.

Previously, when I had an Image view in replacement to the KenBurnsView the Ripple was drawn above the ImageView on the top.

Here is my layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/background"
    android:clickable="true"
    android:orientation="vertical">


    <RelativeLayout
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="@dimen/nav_drawer_header_height">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <com.flaviofaria.kenburnsview.KenBurnsView
                android:id="@+id/header_cover"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/cover_1" />

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <ImageView
                    android:id="@+id/header_toggle"
                    android:layout_width="50dp"
                    android:layout_height="30dp"
                    android:layout_alignParentBottom="true"
                    android:layout_alignParentRight="true"
                    android:layout_marginBottom="10dp"
                    android:layout_marginRight="10dp"
                    android:padding="10dp"
                    android:src="@drawable/toggle_down" />

            </RelativeLayout>

        </FrameLayout>

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/nav_toggle_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"></RelativeLayout>

</LinearLayout>

This is my ripple drawable XML:

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@android:color/white"
    android:drawSelectorOnTop="true"> <!-- ripple color -->

</ripple>

This is how I am adding the ripple:

toggle.setBackground(getResources().getDrawable(R.drawable.ripple));

What is the problem because of which the Ripple gets drwan below the KenBurnsView? It used to work perfectly when there was an ImageView in place of the KenBurnsView?

Aritra Roy
  • 15,355
  • 10
  • 73
  • 107

2 Answers2

3

Unbounded ripples are projected on to the first available background of an ancestor view. Trace up the view hierarchy from the ImageView that's hosting the ripple and you will find that the first available background is on the LinearLayout with identifier drawer.

If you set a transparent background on the RelativeLayout containing your ImageView, the first available background will be one that's rendered above the sibling view and you will get the desired effect.

Side note, that RelativeLayout should be replaced with a FrameLayout, which will provide the same effect with a less expensive layout pass.

alanv
  • 23,966
  • 4
  • 93
  • 80
  • Thank you! This is the first answer I've been able to find that accurately explains why this is happening. Wrapping my image in a FrameLayout and settings it's background to a transparent color made the ripple visible again. – Luke May 13 '17 at 22:38
1

as you can see from your own code ('setBackground') , you're setting the ripple as a BACKGROUND that's why it's being drawn on the background.

ImageView on android API 21 added this "hack" for the ripple android:drawSelectorOnTop="true". But the library you're using didn't add the same hack to it.

There's nothing wrong itself on your code. But this type of behavior cannot be guaranteed by the Android team for 3rd party libraries.

You have a few of options here that will vary on cleanliness, effort and performance:

  1. check ImageView source code, clone the library, add the same hack that imageview used on it for the ripple. After it's working fine, make sure to pull request back to the library.
  2. wrap your KenBurnsView with a FrameLayout and set the ripple using setForeground on the FrameLayout.
  3. clone the library, add option to foreground drawable to it (similar to this How to set foreground attribute to other non FrameLayout view). Also make sure to pull request this valueable code back to the library.
Community
  • 1
  • 1
Budius
  • 39,391
  • 16
  • 102
  • 144
  • Wonderful explanation I would say. I followed the second solution and it worked. A little problem now.. Previously when using setBackground() the ripple used to be circular in shape (even though my ImageView was rectangular) but now using setForeground() the ripple is not square (i mean the boundary). –  May 15 '15 at 16:02
  • 1
    Not sure. Maybe something to do with `android:clipChildren="false" ` and `android:clipToPadding="false"` maybe you should set those to `true` somewhere in the layout to allow the ripple to draw outside the FrameLayout boundaries – Budius May 15 '15 at 16:05
  • 3
    `android:drawSelectorOnTop` isn't a valid attribute on either `ImageView` or `ripple`. Where are you guys getting this information from? – alanv May 15 '15 at 21:31
  • 1
    @alanv aliens, it must be from aliens – Neon Warge Sep 16 '16 at 07:31