L-release-like Touch Ripple animation on pre-L

2019-03-08 06:29发布

问题:

I love the new Touch Ripple animation that was introduced in the new Android L-release as part of the new UI philosophy Material Design.

You can find a video of it in the official design spec under surface reaction here: http://www.google.com/design/spec/animation/responsive-interaction.html

It's basically a dark-gray circle that fades in at the center of the view and grows as it fades out again, eventually filling the whole view with a light gray before disappearing again.

I'd like to add the very same animation to a view in my app that is targetting ICS.

I am a bit clueless on how to add this animation in my application. The official docs at http://developer.android.com/training/animation/index.html don't seem to cover animations that happen "inside a view". Also, I'd like not to use pre-drawn frame animations (one png resource per frame) if possible.

How would I go about implementing that? Any help is highly appreciated!

回答1:

Something I cooked up quickly, far from ideal, but hey, it's something: Gist

Basically drawing a circle based on an animated radius. To get the exact L-effect, some more tweaking should be done. The interesting code:

@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);
}

In their talk "What's new in Android", they talked about that this animation actually happens on a separate "Render thread", which will make its debut in the L-release. This will allow smoother animations, even when the UI thread is busy inflating, or doing anything else expensive.



回答2:

My answer is kind of late but I wanted to share my solution too. 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.