0

Im trying to create the android L preview "ripple" effect on touch event in a view. If i use this code for a button works:

public class MyButton extends Button {

    private float mDownX;
    private float mDownY;

    private float mRadius;

    private Paint mPaint;

    public MyButton(final Context context) {
        super(context);
        init();
    }

    public MyButton(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyButton(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAlpha(100);
    }

    @Override
    public boolean onTouchEvent(@NonNull final MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
            mDownX = event.getX();
            mDownY = event.getY();

            ObjectAnimator animator = ObjectAnimator.ofFloat(this, "radius", 0, getWidth() * 3.0f);
            animator.setInterpolator(new AccelerateInterpolator());
            animator.setDuration(400);
            animator.start();
        }
        return super.onTouchEvent(event);
    }

    public void setRadius(final float radius) {
        mRadius = radius;
        if (mRadius > 0) {
            RadialGradient radialGradient = new RadialGradient(
                    mDownX,
                    mDownY,
                    mRadius * 3,
                    Color.TRANSPARENT,
                    Color.BLACK,
                    Shader.TileMode.MIRROR
            );
            mPaint.setShader(radialGradient);
        }
        invalidate();
    }

    private Path mPath = new Path();
    private Path mPath2 = new Path();

    @Override
    protected void onDraw(@NonNull final Canvas canvas) {
        super.onDraw(canvas);

        mPath2.reset();
        mPath2.addCircle(mDownX, mDownY, mRadius, Path.Direction.CW);

        canvas.clipPath(mPath2);

        mPath.reset();
        mPath.addCircle(mDownX, mDownY, mRadius / 3, Path.Direction.CW);

        canvas.clipPath(mPath, Region.Op.DIFFERENCE);

        canvas.drawCircle(mDownX, mDownY, mRadius, mPaint);
    }
}

Even if not exactly as in Android L preview but it works.. However..if i change Button and i try with a View class not works..is that some what to create that effect in an entire view instead only in a button?

MrEngineer13
  • 38,642
  • 13
  • 74
  • 93
Atlas91
  • 5,754
  • 17
  • 69
  • 141

3 Answers3

2

You need to return true from onTouchEvent() to continue to receive events. Button does this because it's meant to handle click events, whereas the default View does not.

If you set your View to be clickable, you'll get the expected behavior. If you look at the ripple in L-preview, you'll notice that it only occurs on enabled and clickable views.

private void init() {
    mPaint = new Paint();
    mPaint.setAlpha(100);
    setClickable(true);
    setFocusable(true);
}

Alternatively, you can just always call super and then return true:

@Override
public boolean onTouchEvent(@NonNull final MotionEvent event) {
    ...
    super.onTouchEvent(event);
    return true;
}
alanv
  • 23,966
  • 4
  • 93
  • 80
  • Just a question, what is exactly `@NonNull`? what means? – Atlas91 Jul 23 '14 at 07:49
  • It was in your code, so I left it in the example. It's an annotation that in this particular location means the argument is never supposed to be null. – alanv Jul 23 '14 at 07:58
  • Yes i know that was in my code but honestly i never understand what it meant. Thank you :) however, i found a way to do what i wanted and this is the result https://plus.google.com/u/0/+DavideDellai/posts/TqzsypnzudS :) i am going to create a library too to make easier the creation of this effect for each dev. – Atlas91 Jul 23 '14 at 08:01
1

My answer is kind of late and I also shared this solution on this original question too but I also want to share it here. I created another class called TouchEffectAnimator with the idea of Niek Haarman. Thanks to Mr. Haarman by the way.

You can see the class and an example usage of it on this gist. Also I'll explain it simply.

The class contains all the necessary methods and variables in it and creates the same animation that Android L (preview) currently has. For using this class:

  • Create a custom view. (in gist example I created a LinearLayout)
  • Initialise the TouchEffectAnimator object.
  • Define some attributes of it like color, effect type, duration and clip corners size.
  • Call the onTouchEvent method of TouchEffectAnimator inside the view's onTouchEvent.
  • Call the onDraw method of TouchEffectAnimator inside the view's onDraw.

and that's it. But there are two things that should be done for this class to work properly.

  • There should be some OnClickListener on the view to get the UP touch event.
  • There should be a custom or transparent background set to the view. If nothing is set as background the animation is not shown.

I hope it works for you too.

P.S. I created this class for my library project Android FlatUI Kit. You can see the usage of this class in FlatButton class as well.

Community
  • 1
  • 1
eluleci
  • 3,489
  • 1
  • 26
  • 24
0

You can use this library, in order to obtain the 'ripple effect', has support for older devices, api versions >= 14, with some hacks can support also api versions < 14.

Link: material-ripple

Here it is an example of use:

  1. Wrap the interested view:

    <com.balysv.materialripple.MaterialRippleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/MyStyleViewContainer">
    
        <android.support.v7.widget.CardView
            xmlns:card_view="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <!-- content -->
        </android.support.v7.widget.CardView>
    </com.balysv.materialripple.MaterialRippleLayout>
    
  2. Define the style

    <style name="base_ripple_style" parent="AppTheme">
        <item name="mrl_rippleAlpha">0.3</item>
        <item name="mrl_rippleDelayClick">true</item>
        <item name="mrl_rippleDuration">300</item>
        <item name="mrl_rippleFadeDuration">50</item>
        <item name="mrl_rippleOverlay">true</item>
        <item name="mrl_rippleRoundedCorners">5dp</item>
    </style>
    
    <style name="MyStyleViewContainer" parent="base_ripple_style">
        <item name="mrl_rippleColor">@android:color/white</item>
    </style>
    
Kreshnik
  • 2,661
  • 5
  • 31
  • 39