5

I have a TextView inside a CardView. When enabling the ripple effect for Lollipop on the CardView by adding a OnClick event and adding the property:

android:foreground="?android:attr/selectableItemBackground"

It works fine. But after adding a OnClick event to the TextView, the ripple effect still shows up when I click outside of the TextView, but it won't show when clicking on the TextView area.

Is there away to show the ripple even when I click the TextView?

Here is xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context=".MainActivity">

    <android.support.v7.widget.CardView
        android:id="@+id/news_card"
        android:foreground="?android:attr/selectableItemBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/text"
            android:text="Test String"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </android.support.v7.widget.CardView>

</RelativeLayout>

Here is the code:

protected void onCreate (Bundle savedInstanceState) {
    super.onCreate (savedInstanceState);
    setContentView (R.layout.activity_main);

    View v = findViewById (R.id.news_card);
    v.setOnClickListener (new View.OnClickListener () {
        @Override public void onClick (final View v) {

        }
    });

    View textView = findViewById (R.id.text);
    textView.setOnClickListener (new View.OnClickListener () {
        @Override public void onClick (final View v) {

        }
    });
}
Comtaler
  • 1,580
  • 1
  • 15
  • 26
  • The ripple should only show on the element that handles the click. If the entire card isn't clickable, the entire card shouldn't show a ripple. – alanv Jan 28 '15 at 00:01
  • On a user's perspective, the entire card is clickable. But when user clicks on the TextView, it has to do some extra logic first before passing that on to the card's onclick event. – Comtaler Jan 28 '15 at 17:56

1 Answers1

6

One option is to forward the pressed state and hotspot position through to the parent view.

// Since the host view actually supports clicks, you can return false
// from your touch listener and continue to receive events.
myTextView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent e) {
        // Convert to card view coordinates. Assumes the host view is
        // a direct child and the card view is not scrollable.
        float x = e.getX() + v.getLeft();
        float y = e.getY() + v.getTop();

        // Simulate motion on the card view.
        myCardView.drawableHotspotChanged(x, y);

        // Simulate pressed state on the card view.
        switch (e.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                myCardView.setPressed(true);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                myCardView.setPressed(false);
                break;
        }

        // Pass all events through to the host view.
        return false;
    }
});
alanv
  • 23,966
  • 4
  • 93
  • 80
  • 3
    This works. But the animation is not as smooth as the default behavior. I ended up removing the onClickListener on the TextView and implement onTouchListener to do what onClickListener does and return false to allow the CardView to show the ripple effect. – Comtaler Feb 06 '15 at 22:23