经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android 5.0 实现水波扩散效果
来源:jb51  时间:2019/1/31 9:04:19  对本文有异议

本文实例为大家分享了Android 5.0 实现水波扩散效果的具体代码,供大家参考,具体内容如下

该效果是通过自定义界面来实现的

1、首先自定义属性,attrs.xml代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="RippleView">
  4. <attr name="rippleColor" format="color" />
  5. <attr name="rippleAlpha" format="float" />
  6. <attr name="maskAlpha" format="float" />
  7. <attr name="rippleTime" format="integer" />
  8. </declare-styleable>
  9. </resources>

其中属性rippleColor为水波动画的颜色,rippleAlpha为其透明度,rippleTime为动画持续时间,maskAlpha为触摸遮掩层的透明度。

2、自定义RippleView类继承RelativeLayout布局,也可以由需求所定继承于其它类,实现水波扩散效果主要的有两点:水波扩散的绘制和动画

1)水波的绘制其实就是绘制一个圆形

  1. canvas.drawCircle(mDownX, mDownY, mRadius, mRipplePaint);

2)动画效果就是该圆形的绘制从小到大的过程,而该圆形到最大时的半径长度就是当前所在布局的对角线长度:

  1. @Override
  2. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  3. super.onSizeChanged(w, h, oldw, oldh);
  4. // 获取最大半径
  5. mMaxRadius = (float) Math.sqrt(w * w + h * h);
  6. }

动画效果用属性动画ObjectAnimator来实现(ObjectAnimator是android3.0后出现的)如下

  1. mRippleAnim = ObjectAnimator.ofFloat(this, "radius", 0, mMaxRadius);
  2. mRippleAnim.setInterpolator(new AccelerateDecelerateInterpolator());
  3. mRippleAnim.setDuration(mRippleTime);

其中的radius为自定义的属性,在动画执行时会回调对应的方法,只需要在该方法中更新圆形的半径就行了

  1. public void setRadius(final float radius) {
  2. mRadius = radius;
  3. invalidate();
  4. }

RippleView完整代码如下:

  1. public class RippleView extends RelativeLayout {
  2. private int mRippleColor;// 水波颜色
  3. private float mMaskAlpha;// 遮掩透明度
  4. private float mRippleAlpha;// 水波透明度
  5. private int mRippleTime;// 水波动画时间
  6. private ObjectAnimator mRippleAnim;// 显示水波动画
  7. private float mRadius;// 当前的半径
  8. private float mMaxRadius;// 水波最大半径
  9. private float mDownX; // 记录手指按下的位置
  10. private float mDownY;
  11. private boolean mIsMask;
  12. private boolean mIsAnimating;// 是否正在播放动画
  13. private RectF mRect;
  14. private Path mPath;
  15. private Paint mMaskPaint;
  16. private Paint mRipplePaint;
  17. public RippleView(Context context) {
  18. this(context, null);
  19. }
  20. public RippleView(Context context, AttributeSet attrs) {
  21. this(context, attrs, 0);
  22. }
  23. public RippleView(Context context, AttributeSet attrs, int defStyle) {
  24. super(context, attrs, defStyle);
  25. init();
  26. // 获取自定义属性
  27. TypedArray ta = context.obtainStyledAttributes(attrs,
  28. R.styleable.RippleView);
  29. mRippleColor = ta.getColor(R.styleable.RippleView_rippleColor,
  30. mRippleColor);
  31. mMaskAlpha = ta.getFloat(R.styleable.RippleView_maskAlpha, mMaskAlpha);
  32. mRippleAlpha = ta.getFloat(R.styleable.RippleView_rippleAlpha,
  33. mRippleAlpha);
  34. mRippleTime = ta.getInt(R.styleable.RippleView_rippleTime, mRippleTime);
  35. ta.recycle();
  36. initLast();
  37. }
  38. // 初始化方法
  39. private void init() {
  40. mRippleColor = Color.BLACK;
  41. mMaskAlpha = 0.4f;
  42. mRippleAlpha = 0.8f;
  43. mRippleTime = 800;
  44. mPath = new Path();
  45. mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  46. mRipplePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  47. }
  48. // 初始化
  49. private void initLast() {
  50. mMaskPaint.setColor(mRippleColor);
  51. mRipplePaint.setColor(mRippleColor);
  52. mMaskPaint.setAlpha((int) (mMaskAlpha * 255));
  53. mRipplePaint.setAlpha((int) (mRippleAlpha * 255));
  54. }
  55. // 初始化动画
  56. private void initAnim() {
  57. mRippleAnim = ObjectAnimator.ofFloat(this, "radius", 0, mMaxRadius);
  58. mRippleAnim.setInterpolator(new AccelerateDecelerateInterpolator());
  59. mRippleAnim.setDuration(mRippleTime);
  60. mRippleAnim.addListener(new Animator.AnimatorListener() {
  61. @Override
  62. public void onAnimationStart(Animator animator) {
  63. mIsAnimating = true;
  64. }
  65. @Override
  66. public void onAnimationEnd(Animator animator) {
  67. setRadius(0);
  68. mIsMask = false;
  69. mIsAnimating = false;
  70. }
  71. @Override
  72. public void onAnimationCancel(Animator animator) {
  73. }
  74. @Override
  75. public void onAnimationRepeat(Animator animator) {
  76. }
  77. });
  78. }
  79. @Override
  80. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  81. super.onSizeChanged(w, h, oldw, oldh);
  82. // 获取最大半径
  83. mMaxRadius = (float) Math.sqrt(w * w + h * h);
  84. // 获取该类布局范围
  85. mRect = new RectF(0f, 0f, getMeasuredWidth() * 1.0f,
  86. getMeasuredHeight() * 1.0f);
  87. // 初始化动画
  88. initAnim();
  89. }
  90. @Override
  91. public boolean onTouchEvent(MotionEvent event) {
  92. // 按下事件
  93. if (event.getAction() == MotionEvent.ACTION_DOWN) {
  94. mIsMask = true;
  95. invalidate();
  96. } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
  97. invalidate();
  98. }
  99. // 抬起事件
  100. else if (event.getAction() == MotionEvent.ACTION_UP) {
  101. mDownX = event.getX();
  102. mDownY = event.getY();
  103. if (mIsAnimating) {
  104. mRippleAnim.cancel();
  105. }
  106. boolean isInView = mRect.contains(mDownX, mDownY);
  107. if (isInView) {
  108. mRippleAnim.start();
  109. } else {
  110. mIsMask = false;
  111. invalidate();
  112. }
  113. }
  114. return true;
  115. }
  116. @Override
  117. protected void onDraw(Canvas canvas) {
  118. super.onDraw(canvas);
  119. // 绘制遮掩
  120. if (mIsMask) {
  121. canvas.save(Canvas.CLIP_SAVE_FLAG);
  122. mPath.reset();
  123. mPath.addRect(mRect, Path.Direction.CW);
  124. canvas.clipPath(mPath);
  125. canvas.drawRect(mRect, mMaskPaint);
  126. canvas.restore();
  127. }
  128. // 绘制水波
  129. canvas.save(Canvas.CLIP_SAVE_FLAG);
  130. mPath.reset();
  131. mPath.addCircle(mDownX, mDownY, mRadius, Path.Direction.CW);
  132. canvas.clipPath(mPath);
  133. canvas.drawCircle(mDownX, mDownY, mRadius, mRipplePaint);
  134. canvas.restore();
  135. }
  136. // 属性动画回调的方法
  137. public void setRadius(final float radius) {
  138. mRadius = radius;
  139. invalidate();
  140. }
  141. }

界面布局代码

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. xmlns:ripple="http://schemas.android.com/apk/res/com.example.rippleview"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:background="#000000" >
  7. <com.example.rippleview.RippleView
  8. android:layout_width="match_parent"
  9. android:layout_height="100dp"
  10. android:layout_centerInParent="true"
  11. android:background="#ffffff"
  12. android:clickable="true"
  13. ripple:rippleColor="#ababab" >
  14. <TextView
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:layout_centerInParent="true"
  18. android:text="click me"
  19. android:textSize="18sp" />
  20. </com.example.rippleview.RippleView>
  21. </RelativeLayout>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号