自定义View之圆形水波扩散动效
这个效果做出来以后,真的美极了!放在你的应用中,无疑增添了光彩!
效果图
其实,第一种效果,才是产品的需求要的效果。第三种效果,是不是很熟悉?支付宝的咻一咻!哈哈,无意中,我就写出来了。
实现步骤
1.attrs.xml定义属性
<declare-styleable name="WaveView">
<!--圆颜色-->
<attr name="wave_color" format="color"/>
<!--中心圆图片半径-->
<attr name="wave_coreImageRadius" format="integer"/>
<!--波浪圆之间间距,值越小越窄-->
<attr name="wave_width" format="integer"/>
</declare-styleable>
2.WaveView的初始化
/**
* 波浪圆圈颜色
*/
private int mColor = getResources().getColor(R.color.yellow);
/**
* 第一个圆圈的半径(也就是圆形图片的半径)
*/
private int mImageRadius=50;
/**
* 波浪圆之间间距
*/
private int mWidth = 3;
/**
* 最大宽度
*/
private Integer mMaxRadius = 300;
/**
* 是否正在扩散中
*/
private boolean mIsWave = false;
// 透明度集合
private List<Integer> mAlphas = new ArrayList<>();
// 扩散圆半径集合
private List<Integer> mRadius = new ArrayList<>();
private Paint mPaint;
public WaveView(Context context) {
this(context, null);
}
public WaveView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView, defStyleAttr, 0);
mColor = a.getColor(R.styleable.WaveView_wave_color, mColor);
mWidth = a.getInt(R.styleable.WaveView_wave_width, mWidth);
mImageRadius = a.getInt(R.styleable.WaveView_wave_coreImageRadius, mImageRadius);
a.recycle();
}
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
// mAlphas.add(255);
// mRadius.add(0);
}
3.重写onDraw()
@Override
public void onDraw(Canvas canvas) {
// 绘制扩散圆
mPaint.setColor(mColor);
for (int i = 0; i < mAlphas.size(); i++) {
// 设置透明度
Integer alpha = mAlphas.get(i);
mPaint.setAlpha(alpha);
// 绘制波浪圆
Integer radius = mRadius.get(i);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mImageRadius+radius, mPaint);
if (alpha > 0 && mImageRadius+radius < mMaxRadius) {
alpha = (int) (255.0F * (1.0F - (mImageRadius+radius) * 1.0f / mMaxRadius));
mAlphas.set(i, alpha);
mRadius.set(i, radius + 1);
}else if(alpha < 0 && mImageRadius+radius > mMaxRadius){
// 当最外面那个圆达到了View的宽度时,移除,保证内存的回收
mRadius.remove(i);
mAlphas.remove(i);
}
}
// 判断当波浪圆扩散到指定宽度时添加新扩散圆
// if (mRadius.get(mRadius.size() - 1) == mWidth) {
// addWave();
// }
if (mIsWave) {
invalidate();
}
}
思路:一直不停的在根据list中的半径值和alpha值在画对应的圆,list中有多少个圆,就会画出多少个,当alpha的值小于0了,视觉上,人眼看不到了,或者已经到了View的边界,就将他移除。减少内存的占用。
4.提供的一些公共的方法,方便调用
/**
* 开始扩散
*/
public void start() {
mIsWave = true;
invalidate();
}
/**
* 停止扩散
*/
public void stop() {
mIsWave = false;
}
/**
* 是否扩散中
*/
public boolean isWave() {
return mIsWave;
}
/**
* 设置波浪圆颜色
*/
public void setColor(int colorId) {
mColor = colorId;
}
/**
* 设置波浪圆之间间距
*/
public void setWidth(int width) {
mWidth = width;
}
/**
* 设置中心圆半径
*/
public void setMaxRadius(int maxRadius) {
mMaxRadius = maxRadius;
}
public void setImageRadius(int imageRadius) {
mImageRadius = imageRadius;
}
public void addWave(){
mAlphas.add(255);
mRadius.add(0);
}
5.Activity中的调用和xml布局
WaveActivity.java
private ImageView head;
private WaveView wave;
private ScaleAnimation scaleAnimation;
private MediaPlayer mPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wave);
scaleAnimation = new ScaleAnimation(1.2f, 1f, 1.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(500);
scaleAnimation.setFillAfter(true);
wave = (WaveView) findViewById(R.id.wave);
head = (ImageView) findViewById(R.id.head);
mPlayer = MediaPlayer.create(this, R.raw.water_wave);
head.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
wave.addWave();
head.startAnimation(scaleAnimation);
if(mPlayer.isPlaying()){
mPlayer.stop();
try {
mPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
mPlayer.start();
}
});
wave.start();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
wave.setImageRadius(head.getWidth()/2);
}
activity_wave.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
>
<com.dx.demi.view.WaveView
android:id="@+id/wave"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:wave_color="@color/yellow"
app:wave_coreImageRadius="30"
app:wave_width="40"/>
<ImageView
android:id="@+id/head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/user"
android:layout_centerInParent="true"/>
</RelativeLayout>
6.需要注意的细节
/**
* 获取View的宽高在构造方法中拿不到的,getWidth(),getHeight()都会为零
* @param hasWindowFocus
*/
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
mMaxRadius = getWidth() > getHeight() ? getHeight() / 2 : getWidth() / 2;
invalidate();
}
/**
* 防止window是去焦点时,也就是应用在后台时,停止View的绘制
*/
@Override
public void invalidate() {
if (hasWindowFocus()) {
super.invalidate();
}
}
三种效果的切换
1.我目前贴的代码实现的是效果3(咻一咻):点击图片,图片会放大,同时会播放背景音乐(网上随便找了个还听得过去的),并增加一个新的波浪圆。
2.效果1:打开View的界面,每个一段固定的距离,就会产生一个新的波浪圆。波浪圆是空心的。这个只要设置画笔的风格为STROKE,并设置StrokeWidth。Activity中注释掉动画,注释掉点击事件,注释掉音乐播放。但是要记得一开始就得添加新圆,不然啥都没有。毕竟不像效果3那样,点击图片才有。
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mAlphas.add(255);
mRadius.add(0);
3.效果2:打开View的界面,每个一段固定的距离,就会产生一个新的波浪圆。波浪圆是实心的。Activity中注释掉动画,注释掉点击事件,注释掉音乐播放。设置画笔的风格为FILL就OK了,默认风格就是FILL。
总结:
在完成这个自定义View的时候,花了很长时间。我也不是一开始就是这样的一个思路。没有想到过用集合来存放半径,没有第一时间想到getWidth()的值在构造方法中会获取不到.所以还是得多想,多尝试。我们才会进步,提高!在自定义View时,一定要明白一个真理:”onDraw()方法重新调用时,会抹去上一次绘制过的图像“。有些地方,我写的可能不是很好,还需要优化。欢迎点评!
源代码链接
自定义View之圆形水波扩散动效的更多相关文章
- 自定义View之一圆形图片
自定义View的方法 对现有控件进行扩展 通过组合来实现新的控件 重写View来实现全新的控件 本篇文章主要讲对现有控件的扩展 1.圆形图片控件 自定义View,对ImageView的扩展 重写onD ...
- 自定义View,圆形头像
1. 效果图 2. xml中 <com.etoury.etoury.ui.view.CircleImg android:id="@+id/user_info_head_img" ...
- android自定义View绘制圆形头像与椭圆头像
要实现这两种效果,需要自定义View,并且有两种实现方式. 第一种: public class BitmapShaders extends View { private BitmapSh ...
- Android绘图机制(一)——自定义View的基础属性和方法
Android绘图机制(一)--自定义View的基础属性和方法 自定义View看起来,确实看起来高深莫测,很多Android开发都不是特别在行这一块,这里面的逻辑以及一些绘画都是有一点难的,说一下我目 ...
- 通过圆形载入View了解自定义View
这是自定义View的第一篇文章,通过制作简单的自定义View来了解自定义View的流程. 自定义View是Android学习和开发中必不可少的一部分.通过自定义View我们可以制作丰富绚丽的控件,自定 ...
- Android 自定义 View 圆形进度条总结
Android 自定义圆形进度条总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 微信公众号:牙锅子 源码:CircleProgress 文中如有纰漏,欢迎大家留言指出. 最近 ...
- Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)
Android 高手进阶(21) 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请注明地址:http://blog.csdn.net/xiaanming/article/detail ...
- Android 自定义View修炼-Android实现圆形、圆角和椭圆自定义图片View(使用BitmapShader图形渲染方法)
一.概述 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的.实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader.本文直接继 ...
- Android 自定义view --圆形百分比(进度条)
转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50334595 注:本文由于是在学习过程中写的,存在大量问题(overdraw onDr ...
随机推荐
- Android github XListView 分析(2-3)
本文内容 概述 XListView UML 图 下载 github XListView 概述 我们经常能见到 app 中的 listview 有"下拉更多"和"上拉加载& ...
- 删除数据库mysql
drop命令用于删除数据库. drop命令格式:drop database <数据库名>; 例如,删除名为 xhkdb的数据库:mysql> drop database xhkdb; ...
- CXF实战之拦截器Interceptor(四)
拦截器(Interceptor)是CXF功能最基本的扩展点,能够在不正确核心模块进行改动的情况下.动态加入非常多功能.拦截器和JAX-WS Handler.Filter的功能相似,当服务被调用时.就会 ...
- GetParam(name)
function GetParam(name) { var match = new RegExp(name + "=*([^&]+)*", "i").e ...
- Android 之 Fagment 完全解析
Android 上的界面展示都是通过 Activity 实现的,Activity 非常常用,不再赘述.但是 Activity 也有它的局限性,同样的界面在手机上显示可能很好看,在平板上就未必了,因为平 ...
- VO、DTO与领域模型的概念
业务对象模型(也叫领域模型 domain model)是描述业务用例实现的对象模型.它是对业务角色和业务实体之间应该如何联系和协作以执行业务的一种抽象.业务对象模型从业务角色内部的观点定义了业务用例. ...
- JDK5.0 特性-线程任务执行架构 ScheduledExecutorService
来自:http://www.cnblogs.com/taven/archive/2011/12/17/2291469.html import java.util.concurrent.Callable ...
- cache-control 缓存
1.服务端设置 2. 3.所以一般设置css/js等静态文件加一个md5码. 4.优先级问题 如果服务器端同时设置了Etag和Expires 时,Etag原理同样,即与Last-Modified/Et ...
- 【Java】监控远程服务器JVM
今天在用JMeter进行测试的时候,发现线程并发量到50的时候会导致阻塞情况,于是需要监控远程JVM,那么如何监控远程JVM呢? 首先,找到启动计量引擎的sh文件,例如我目前的计量引擎启停文件为str ...
- SpringMVC 参数中接收数组、List写法
本文使用SpringMVC版本: org.springframework:spring-web:4.3.9.RELEASE 写法及说明(示例代码的类上的注解是@RestController,所以不需要 ...