先上效果图

点击中间的按钮后,像外发散水波纹,再次点击水波纹消失。

实现原理

当点击按钮后,我们隔一段时间执行一个RippleCircleView的动画,动画包括扩大和透明度,通过PropertyValuesHolder将动画封装到一起,核心就是动画的实现

代码实现

首先是RippleCircleView,RippleCircleView啥也不干,就画一个圆,这个圆也是水波纹的灵魂,用来扩散的圆。


public class RippleCircleView extends View {private RippleAnimationView mRippleAnimationView;public RippleCircleView(RippleAnimationView rippleAnimationView) {super(rippleAnimationView.getContext());mRippleAnimationView = rippleAnimationView;}public RippleCircleView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);float radius = Math.min(getWidth(), getHeight()) / 2;canvas.drawCircle(radius, radius, radius - RippleAnimationView.STROKE_WIDTH, mRippleAnimationView.getPaint());}
}

有了水波纹的圆之后接下来我们实现水波纹的父布局,其父布局继承自相对布局,在初始化的时候将动画创建好,同时为了避免动画多次执行,添加一个标志位,并向外暴露开始和关闭动画的方法。

public class RippleAnimationView extends RelativeLayout {private Paint mPaint;int radius;public static final int STROKE_WIDTH = 5;int rippleColor;List<View> views = new ArrayList<>();private boolean animationRunning = false;public RippleAnimationView(Context context) {super(context);}public RippleAnimationView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init(context, attrs);}private void init(Context context, AttributeSet attrs) {mPaint = new Paint();mPaint.setAntiAlias(true);//抗锯齿radius = 54;rippleColor = ContextCompat.getColor(context, R.color.rippleColor);mPaint.setStrokeWidth(STROKE_WIDTH);mPaint.setStyle(Paint.Style.FILL);mPaint.setColor(rippleColor);//        延迟时间int rippleDuration = 3500;int singleDelay = rippleDuration / 4;//间隔时间 (上一个波纹  和下一个波纹的)RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(radius + STROKE_WIDTH, radius + STROKE_WIDTH);params.addRule(CENTER_IN_PARENT);for (int i = 0; i < 4; i++) {RippleCircleView rippleCircleView = new RippleCircleView(this);addView(rippleCircleView, params);views.add(rippleCircleView);PropertyValuesHolder aplhaHolder = PropertyValuesHolder.ofFloat("Alpha", 1, 0);PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofFloat("scaleX", 10);PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofFloat("scaleY", 10);ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(rippleCircleView, aplhaHolder, scaleXHolder, scaleYHolder);animator.setDuration(rippleDuration);animator.setStartDelay(i * singleDelay);animator.setRepeatMode(ObjectAnimator.RESTART);animator.setRepeatCount(ObjectAnimator.INFINITE);rippleCircleView.setTag(animator);}}//启动动画   //停止动画public void startRippleAnimation() {if (!animationRunning) {for (View rippleView : views) {rippleView.setVisibility(VISIBLE);((ObjectAnimator) rippleView.getTag()).start();}animationRunning = true;}}public void stopRippleAnimation() {if (animationRunning) {Collections.reverse(views);for (View rippleView : views) {rippleView.setVisibility(INVISIBLE);((ObjectAnimator) rippleView.getTag()).end();((ObjectAnimator) rippleView.getTag()).cancel();}animationRunning = false;}}public boolean isAnimationRunning() {return animationRunning;}public Paint getPaint() {return mPaint;}
}

最后就是在activity中使用,先上布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorPrimary"android:orientation="vertical"><com.itzb.wangyimusicanimdemo.ripple.RippleAnimationViewandroid:id="@+id/layout_RippleAnimation"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/ImageView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_centerVertical="true"android:src="@mipmap/music" /><TextViewandroid:id="@+id/tv1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/ImageView"android:gravity="center"android:text="点击识别音乐"android:textColor="@android:color/white"android:textSize="14sp" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/tv1"android:layout_marginTop="10dp"android:gravity="center"android:text="听歌识曲,识别你周围播放的歌"android:textColor="@android:color/darker_gray"android:textSize="12sp" /></com.itzb.wangyimusicanimdemo.ripple.RippleAnimationView></RelativeLayout>

最后就是在点击按钮的时候播放动画即可,再次点击停止动画

public class RippleActivity extends AppCompatActivity {private ImageView imageView;RippleAnimationView rippleAnimationView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_ripple);imageView = (ImageView) findViewById(R.id.ImageView);rippleAnimationView = (RippleAnimationView) findViewById(R.id.layout_RippleAnimation);imageView.setOnClickListener(view -> {if (rippleAnimationView.isAnimationRunning()) {rippleAnimationView.stopRippleAnimation();} else {rippleAnimationView.startRippleAnimation();}});}
}

Demo地址:https://github.com/987570437/WangYiMusicAnimDemo

自定义View之网易云音乐听歌识曲水波纹动画相关推荐

  1. 听歌识曲java_Android自定义View之继承扩展(仿网易云音乐听歌识曲)

    前言 上篇文章说到了自定义View的组合实战,链接:Android自定义View之组合实战(以支付宝页面为例) ,感兴趣的同学可以看看.今天要分享的是一个模仿网易云音乐听歌识曲界面的自定义View,实 ...

  2. Chrome插件:网易云音乐听歌识曲

    大家好,我是若川.持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...

  3. Axure教程(中级):网易云音乐听歌识曲效果模仿

    本教程给大家分享一下模仿[网易云音乐]APP的听歌识曲界面效果 做法如下,如有雷同,纯属默契: 一.页面布局 从左侧元件库拉入一个[椭圆形],尺寸为100*100,填充色为红色,再复制4个作为声波圆圈 ...

  4. 仿网易音乐听歌识曲-麦克风动画

    仿网易音乐听歌识曲-麦克风动画 最近准备做一个关于麦克风的类库,平时听歌也基本用网易音乐,发现了这个效果挺不错的,所以实现收集起来. 一.效果图 二.实现思路分析 透明度变换的体现: 半径不断扩散: ...

  5. android bitmap转图片_带你用Android自定义View实现网易云音乐宇宙尘埃特效

    作者:Mlx, 链接:https://juejin.im/post/6871049441546567688 前言 前段时间,女朋友用网易云音乐的时候看到一个宇宙尘埃特效,说很好看,想要让我给她开VIP ...

  6. 网易云音乐听歌量爬虫(免登陆版)

    最近学习了一下爬虫的原理和基本的思路, 并且利用selenium + Python + Chrome 进行了一系列的爬虫. 最开始的想法是, 想每天爬取自己网易云音乐的一些数据, 比如每天听歌量, 之 ...

  7. 腾讯云函数 python_利用腾讯云函数进行网易云音乐听歌打卡

    腾讯云函数官网 1.找到腾讯云函数控制台,并新建函数(地区任选,这里以广州为例) 2.新建空白函数,函数名称随意填写,运行环境选择Python3.6 为什么不用PHP,因为PHP要执行的全部任务全部通 ...

  8. 非常使用的网易云打卡系统, 网易云音乐打卡,网易云音乐听歌300首, 网易云打卡一键听300首歌

    非常实用的网易云音乐打卡,网易云音乐一键打卡300首歌曲 定时完成网易云音乐打卡,也可托管完成. 一键打卡及可完成听歌任务 升级速度杠杠的! 注意事项: 1.仅支持网易云手机号码登录的用户 2.如果是 ...

  9. Android自定义View——仿网易云音乐留声机效果

    //自定义类 public class GramophoneView extends View {/*** 尺寸计算设计说明:* 1.唱片有两个主要尺寸:中间图片的半径.黑色圆环的宽度.* 黑色圆环的 ...

最新文章

  1. 360浏览器调用selenium
  2. oracle学习小知识点总结
  3. 机械制图中外螺纹的画法_机械制图中图纸上的各种符号代表什么意思?
  4. 《STL源码剖析》学习--6章--_rotate算法分析
  5. 经典算法题每日演练——第二十一题 十字链表
  6. el-table中设置max-height属性使其固定表头
  7. php 数组移除指定健,php删除数组指定键的方法
  8. 《Python Cookbook 3rd》笔记(1.9):查找两字典的相同点
  9. mysql选择前12周_第十二周作业
  10. python是交互式语言吗_什么是Python交互式解释器
  11. java中GC的基本概念
  12. mysql 用一个表更新另一个表
  13. 类库从自带的配置文件中获取信息(DLL文件 获取 DLL文件自带的配置信息) z...
  14. Mac OSX 常用软件下载页面集锦(持续更新)
  15. Arrays.sort(arr, (a, b) -> a - b)是对数组进行排序
  16. TTML(IMSC)字幕
  17. 华氏温度转换为摄氏温度,c语言实例一
  18. 数据分析案例-大数据相关招聘岗位可视化分析
  19. 我该如何拯救你,我的考研?
  20. 如何通过微信小程序进行更加有效的电商营销?

热门文章

  1. sonar (default-cli) on project webgoat-parent: Not inside a Git work tree 错误以及解决方案
  2. 百度飞桨亮相2019 AIIA,四大领先技术剑指落地引开发者点赞
  3. 看机器学习如何还原图像色彩
  4. 关于assert函数的调用警告:implicit declaration of function 'ASSERT' is invalid in C99
  5. Android shell脚本自动启动app,关闭app,遇到crash自动停止
  6. A5SHB,A5SHB芯片三极管规格书
  7. html5 lineheight属性,深入理解line-height属性
  8. 各种重力场模型下载网站
  9. 移动端知网下文献并投屏PC端阅读
  10. cosolog打印带样式的文字及图片