Search code examples
androidnine-patchrippledrawable

Ripple effect drawable is distorted when applied over 9patch background


I have a 9 patch drawable which I want to use as a background on a view. I want the view to show a ripple effect that follows the outline of a 9 patch when the view is clicked. Here's my activity, layout, and drawable code.

MainActivity.kt:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val click = findViewById<ConstraintLayout>(R.id.container)
        click.setOnClickListener { Toast.makeText(this, "Clicked", Toast.LENGTH_SHORT).show() }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.antonc.testapp.MainActivity">

    <android.support.constraint.ConstraintLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="8dp"
        android:paddingStart="8dp"
        android:paddingEnd="8dp"
        android:paddingTop="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:background="@drawable/tooltip_background"
        android:backgroundTint="#2681d8"
        tools:layout_editor_absoluteX="8dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello test test !!!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            />

    </android.support.constraint.ConstraintLayout>

</android.support.constraint.ConstraintLayout>

tooltip_background.xml:

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

tooltip_left_top.9.png:

tooltip_left_top.9.png

But when I click on it, the ripple drawable is very distorted, as if it's stretched to the view size without observing the stretch rules of 9 patch. How should I configure the ripple to make it be the same as the background?:

Result


Solution

  • Update: I have reworked the answer to refine the issue. The following has been edited to reflect the changes.

    TL;DR Do not use android:backgroundTint for ripple backgrounds based on nine-patch drawables at least for API 28. Set the tint in code.


    This issue has something to do with the background tint. I will explain how I came to this conclusion by referring to the following video.

    enter image description here

    I will refer to the bubbles as view1 through view4 from top to bottom. I changed from your nine-patch to better see the patches since your nine-patch was mostly black.

    View1, when click, shows the appropriate ripple effect. It has a ripple background but no background tint.

    View2 is what you are seeing with your background - it is just messed up. This view has a background tint set in XML.

    The height of view3 has been forced to the height of view1 to see how the ripple looks. As you can see, the ripple looks right for the height. It is the non-ripple background image that is distorted.

    View4 is the same as view2 except that it has the tint for RippleDrawable added programmatically. As you can see, this view looks and behaves as it should.

    Bottom line? Don't set the background tint for a nine-patch in XML. Set it in code. Is this a bug? Maybe.

    Here is the support code for the video above.

    activity_main.xml

    <ScrollView 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FFFFFFFF"
        android:fillViewport="true"
        android:orientation="vertical"
        android:padding="16dp"
        tools:context=".MainActivity">
    
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            tools:context=".MainActivity">
    
            <ImageView
                android:id="@+id/imageView1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:background="@drawable/bubble_background"
                android:clickable="true" />
    
            <ImageView
                android:id="@+id/imageView2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:background="@drawable/bubble_background"
                android:backgroundTint="@color/background_tint"
                android:clickable="true" />
    
            <ImageView
                android:id="@+id/imageView3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:background="@drawable/bubble_background"
                android:backgroundTint="@color/background_tint"
                android:clickable="true" />
    
            <ImageView
                android:id="@+id/imageView4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:background="@drawable/bubble_background"
                android:clickable="true" />
    
        </LinearLayout>
    </ScrollView>
    

    bubble_background.xml

    <ripple 
        android:color="#33000000">
        <item android:drawable="@drawable/ninepatch_bubble">
        </item>
    </ripple>
    

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
        private LinearLayout mLayout;
        private ImageView mImageView1;
        private ImageView mImageView2;
        private ImageView mImageView3;
        private ImageView mImageView4;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mLayout = findViewById(R.id.layout);
            mImageView1 = findViewById(R.id.imageView1);
            mImageView2 = findViewById(R.id.imageView2);
            mImageView3 = findViewById(R.id.imageView3);
            mImageView4 = findViewById(R.id.imageView4);
    
            int bgTint = getResources().getColor(R.color.background_tint);
            RippleDrawable rippleDrawable =(RippleDrawable) mImageView4.getBackground();
            rippleDrawable.getDrawable(0).setTint(bgTint);
            mImageView4.setBackground(rippleDrawable);
    
            mLayout.post(new Runnable() {
                @Override
                public void run() {
                    mImageView3.getLayoutParams().height = mImageView1.getMeasuredHeight();
                    mLayout.requestLayout();
                }
            });
        }
    }
    

    colors.xml
    These were added to colors.xml:

    <color name="background_tint">#2681d8</color>
    <color name="ripple_tint">#33000000</color>
    

    ninepatch_bubble.9.png

    enter image description here