在L版本之前实现类似L版本中的触摸涟漪动画

17

我喜欢新的Touch Ripple动画,它是Android L-release中一部分全新UI设计哲学Material Design。

您可以在官方设计规范中的“表面反应”下找到它的视频:http://www.google.com/design/spec/animation/responsive-interaction.html

这基本上是一个深灰色的圆,在视图中心淡入并随着淡出而变大,最终用浅灰色填满整个视图,然后再次消失。

我想将完全相同的动画添加到我的应用程序中的一个视图中,该视图面向ICS。

我不太清楚如何在我的应用程序中添加此动画。官方文档网址为http://developer.android.com/training/animation/index.html,似乎没有涵盖“视图内发生的动画”。 如果可能的话,我不希望使用预先绘制的帧动画(每帧一个png资源)。

我该如何实现呢? 非常感激任何帮助!


我建议等到明天(新的L相关API发布后)再看看是否有支持库来支持这个功能。 - Bryan Herbst
最好的方法是使用自定义drawable。请参阅我的先前答案:http://stackoverflow.com/questions/24213356/animating-actionbars-icon/24214040#24214040(确保还阅读了答案的评论)。 - Budius
2个回答

18

我快速制作了一些东西,离理想还很远,但是嘿,这总比没有好: Gist

基本上是根据动态半径绘制圆形。要获得精确的L效果,需要进行一些微调。有趣的代码如下:

@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);
}
在他们的演讲"Android的新特性"中,他们提到这个动画实际上发生在一个单独的"渲染线程"上,在L版本中首次亮相。这将允许更平滑的动画,即使UI线程正在忙于膨胀或执行其他昂贵的操作。

谢谢!我想最终会结合您的回答和Budius的评论来使用。 - FD_
你的想法很棒,但是当用户触摸按钮时,渐变应该保持不变,对吧? - harveyslash
没有渲染线程对于早期的设备是否会有明显的性能影响? - Xiao

5

虽然我的回答有点晚了,但我也想分享一下我的解决方案。我创建了另一个名为TouchEffectAnimator的类,其灵感来自Niek Haarman。顺便说一下,感谢Haarman先生。

您可以在此处的gist中查看该类及其示例用法。同时我将简单地解释一下。

该类包含所有必要的方法和变量,并创建与Android L(preview)当前相同的动画。要使用此类:

  • 创建自定义视图(在示例中,我创建了一个LinearLayout)
  • 初始化TouchEffectAnimator对象。
  • 定义它的一些属性,如颜色、效果类型、持续时间和剪辑角大小。
  • 在触摸事件中调用TouchEffectAnimator的onTouchEvent方法。
  • 在view的onDraw中调用TouchEffectAnimator的onDraw方法。

就是这样。但是,为使此类正常工作,需要完成两件事情。

  • 应该在视图上设置一些OnClickListener以获取UP触摸事件。
  • 应该为视图设置自定义或透明背景。如果没有设置任何背景,则不会显示动画。

希望这对您也有用。

P.S. 我为我的库项目Android FlatUI Kit创建了这个类。您还可以在FlatButton类中看到此类的用法。


很好,谢谢你分享这个,我打算尝试调整你的TouchEffectAnimator,它完美地工作! - 2Dee
这个工作非常棒,除了我观察到的一个小不一致。如果第一次按按钮是快速的(state_pressed时间非常短),动画就不正确。 - Sreeraj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接