原文链接 https://mp.weixin.qq.com/s/M19tp_ShOO6esKdozi7Nlg

两种方式实现类似水波扩散效果,先上图为敬

  1. 自定义view实现
  2. 动画实现

自定义view实现

思路分析:通过canvas画圆,每次改变圆半径和透明度,当半径达到一定程度,再次从中心开始绘圆,达到不同层级的效果,通过不断绘制达到view扩散效果

private Paint centerPaint; //中心圆paint
private int radius = 100; //中心圆半径
private Paint spreadPaint; //扩散圆paint
private float centerX;//圆心x
private float centerY;//圆心y
private int distance = 5; //每次圆递增间距
private int maxRadius = 80; //最大圆半径
private int delayMilliseconds = 33;//扩散延迟间隔,越大扩散越慢
private List<Integer> spreadRadius = new ArrayList<>();//扩散圆层级数,元素为扩散的距离
private List<Integer> alphas = new ArrayList<>();//对应每层圆的透明度

style文件里自定义属性

<declare-styleable name="SpreadView">
<!--中心圆颜色-->
<attr name="spread_center_color" format="color" />
<!--中心圆半径-->
<attr name="spread_radius" format="integer" />
<!--扩散圆颜色-->
<attr name="spread_spread_color" format="color" />
<!--扩散间距-->
<attr name="spread_distance" format="integer" />
<!--扩散最大半径-->
<attr name="spread_max_radius" format="integer" />
<!--扩散延迟间隔-->
<attr name="spread_delay_milliseconds" format="integer" />
</declare-styleable>

初始化


public SpreadView(Context context) {
this(context, null, 0);
} public SpreadView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
} public SpreadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpreadView, defStyleAttr, 0);
radius = a.getInt(R.styleable.SpreadView_spread_radius, radius);
maxRadius = a.getInt(R.styleable.SpreadView_spread_max_radius, maxRadius);
int centerColor = a.getColor(R.styleable.SpreadView_spread_center_color, ContextCompat.getColor(context, R.color.colorAccent));
int spreadColor = a.getColor(R.styleable.SpreadView_spread_spread_color, ContextCompat.getColor(context, R.color.colorAccent));
distance = a.getInt(R.styleable.SpreadView_spread_distance, distance);
a.recycle(); centerPaint = new Paint();
centerPaint.setColor(centerColor);
centerPaint.setAntiAlias(true);
//最开始不透明且扩散距离为0
alphas.add(255);
spreadRadius.add(0);
spreadPaint = new Paint();
spreadPaint.setAntiAlias(true);
spreadPaint.setAlpha(255);
spreadPaint.setColor(spreadColor);
}

确定圆心位置

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//圆心位置
centerX = w / 2;
centerY = h / 2;
}

自定义view的绘制


@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < spreadRadius.size(); i++) {
int alpha = alphas.get(i);
spreadPaint.setAlpha(alpha);
int width = spreadRadius.get(i);
//绘制扩散的圆
canvas.drawCircle(centerX, centerY, radius + width, spreadPaint); //每次扩散圆半径递增,圆透明度递减
if (alpha > 0 && width < 300) {
alpha = alpha - distance > 0 ? alpha - distance : 1;
alphas.set(i, alpha);
spreadRadius.set(i, width + distance);
}
}
//当最外层扩散圆半径达到最大半径时添加新扩散圆
if (spreadRadius.get(spreadRadius.size() - 1) > maxRadius) {
spreadRadius.add(0);
alphas.add(255);
}
//超过8个扩散圆,删除最先绘制的圆,即最外层的圆
if (spreadRadius.size() >= 8) {
alphas.remove(0);
spreadRadius.remove(0);
}
//中间的圆
canvas.drawCircle(centerX, centerY, radius, centerPaint);
//TODO 可以在中间圆绘制文字或者图片 //延迟更新,达到扩散视觉差效果
postInvalidateDelayed(delayMilliseconds);
}

xml样式

<com.airsaid.diffuseview.widget.SpreadView
android:id="@+id/spreadView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:spread_center_color="@color/colorAccent"
app:spread_delay_milliseconds="35"
app:spread_distance="5"
app:spread_max_radius="90"
app:spread_radius="100"
app:spread_spread_color="@color/colorAccent" />

效果图

中心圆处可以自定义写文字,画图片等等...

动画实现

思路分析:通过动画实现,imageView不停做动画缩放+渐变

最中心的imageView保持不变

中间一层imageView从原始放大到1.4倍,同时从不透明变为半透明

最外层的imageView从1.4倍放大到1.8倍,同时从半透明变为全透明

利用shape画一个圆,作为动画基础视图

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="65dp"/>
<solid android:color="@color/colorAccent"/>
</shape>

布局视图

<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--中心imageView-->
<ImageView
android:id="@+id/iv_wave"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_gravity="center"
android:background="@drawable/shape_circle" />
<!--中间的imageView-->
<ImageView
android:id="@+id/iv_wave_1"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_gravity="center"
android:background="@drawable/shape_circle" />
<!--最外层imageView-->
<ImageView
android:id="@+id/iv_wave_2"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_gravity="center"
android:background="@drawable/shape_circle" />
</FrameLayout>

中间imageView的动画

private void setAnim1() {
AnimationSet as = new AnimationSet(true);
//缩放动画,以中心从原始放大到1.4倍
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.4f, 1.0f, 1.4f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
//渐变动画
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.5f);
scaleAnimation.setDuration(800);
scaleAnimation.setRepeatCount(Animation.INFINITE);
alphaAnimation.setRepeatCount(Animation.INFINITE);
as.setDuration(800);
as.addAnimation(scaleAnimation);
as.addAnimation(alphaAnimation);
iv1.startAnimation(as);
}

最外层imageView的动画

private void setAnim2() {
AnimationSet as = new AnimationSet(true);
//缩放动画,以中心从1.4倍放大到1.8倍
ScaleAnimation scaleAnimation = new ScaleAnimation(1.4f, 1.8f, 1.4f, 1.8f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
//渐变动画
AlphaAnimation alphaAnimation = new AlphaAnimation(0.5f, 0.1f);
scaleAnimation.setDuration(800);
scaleAnimation.setRepeatCount(Animation.INFINITE);
alphaAnimation.setRepeatCount(Animation.INFINITE);
as.setDuration(800);
as.addAnimation(scaleAnimation);
as.addAnimation(alphaAnimation);
iv2.startAnimation(as);
}

效果图

相比较而言,自定义view的效果更好点,动画实现起来更方便点。

两种方式实现的扩散效果介绍完毕,具体项目里还是要按需变动的。

欢迎关注我的博客:https://blog.manjiexiang.cn/

同时欢迎关注微信公众号

Android 两种方式实现类似水波扩散效果的更多相关文章

  1. android两种方式获取AsyncTask返回值

    获取AsyncTask返回值,在Activity中使用. 引用链接:https://www.oschina.net/code/snippet_725438_49858#72630 [1].[代码] [ ...

  2. [Android] Android ViewPager 中加载 Fragment的两种方式 方式(二)

    接上文: https://www.cnblogs.com/wukong1688/p/10693338.html Android ViewPager 中加载 Fragmenet的两种方式 方式(一) 二 ...

  3. [Android] Android ViewPager 中加载 Fragment的两种方式 方式(一)

    Android ViewPager 中加载 Fragmenet的两种方式 一.当fragment里面的内容较少时,直接 使用fragment xml布局文件填充 文件总数 布局文件:view_one. ...

  4. android 发送短信的两种方式,以及接收报告和发送报告

               android发送短信,以及接收报告和发送报告          android中发送短信其实有两种方式,这个和打电话类似,大家可以了解一下:    一.调起系统发短信功能    ...

  5. Unity调用Android的两种方式:其一、调用jar包

    unity在Android端开发的时候,免不了要调用Java:Unity可以通过两种方式来调用Android:一是调用jar.二是调用aar. 这篇文章主要讲解怎么从无到有的生成一个jar包,然后un ...

  6. Android ScrollView监听滑动到顶部和底部的两种方式(你可能不知道的细节)

    Android ScrollView监听滑动到顶部和底部,虽然网上很多资料都有说,但是不全,而且有些细节没说清楚 使用场景: 1. 做一些复杂动画的时候,需要动态判断当前的ScrollView是否滚动 ...

  7. Xamarin Android Activity全屏的两种方式

    方式一 直接在Activity的Attribute中定义 如下 在 MainActivity 中 [Activity(Label = "app", MainLauncher = t ...

  8. Android Activity返回键控制的两种方式

    Android Activity返回键监听的两种方式 1.覆写Activity的OnBackPressed方法 官方解释: Called when the activity has detected ...

  9. Android请求服务器的两种方式--post, get的区别

    android中用get和post方式向服务器提交请求_疯狂之桥_新浪博客http://blog.sina.com.cn/s/blog_a46817ff01017yxt.html Android提交数 ...

随机推荐

  1. java运行机制、Jdk版本及Java环境变量

    一.语言特性 计算机高级语言按程序的执行方式可分为:编译型和解释型两种.编译型的语言是指使用专门的编译器,针对特定的平台(操作系统)一次性翻译成被该平台硬件执行的机器码,并包装成该平台可执行性程序文件 ...

  2. Java基础:内存模型

    1. 引言 2. Java内存模型 3. 内存间的交互操作 1. 引言 考虑到计算机组成的内容: 原始的计算机是CPU用于计算+硬盘用于存储,由于CPU的高速发展和硬盘的缓慢发展,高速的存储需要持续供 ...

  3. python 面向对象进阶之元类metaclass

    一:知识储备 exec exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定,默认为globals() 参数三:局部作用域(字典形式),如果不指定,默认为local ...

  4. 【踩坑】iconfont使用异常bug

    你见过html页面上'x'字符变成打印机图标么?一般人应该没有. -----------------------诡异bug----------------------- 今天测试报了一个bug,说页面 ...

  5. redis的持久化之RDB的配置和原理

    Redis优秀的性能是由于其将所有的数据都存储在内存中,同样memcached也是这样做的,内存中的数据会在服务器重启后就没有了,也就是不能保证持久化.但是为什么Redis能够脱颖而出呢,很大程度上是 ...

  6. MongoDB学习--安装与管理

    一.简介 MongoDB是一种强大.灵活,且易于扩展的通用型数据库.他能扩展出非常多的功能.如二级索引(secondary index).范围查询(range query).排序.聚合(aggrega ...

  7. 设计模式之策略模式(Strategy Pattern)

    模板方法是通过继承实现的,在父类中定义出算法的骨架,将不同点在子类中实现.而策略模式是通过接口实现的,策略中定义了完整的算法.它们有点像啊-- 策略模式的定义 策略模式(Strategy Patter ...

  8. spring和hibernate整合之---java.lang.ClassNotFoundException: javax.el.ELManager 大坑

    今天整合spring和hibernate, 本着使用最高版本的原则, 使用了hibernate-validator  6.0.1.Final, tomcat是7.0.56, 启动时出现如下错误. 经过 ...

  9. linux设备驱动之字符设备驱动模型(2)

    在上一篇中我们已经了解了字符设备驱动的原理,也了解了应用层调用内核函数的机制,但是我们每次操作设备,都必须首先通过mknod命令创建一个设备文件名,比如说我们要打开u盘,硬盘等这些设备,难道我们还要自 ...

  10. 0517JS综合练习、挂事件练习

    <!DOCTYPE html><html>    <head>        <meta charset="UTF-8">      ...