自定义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 ...
随机推荐
- c++ 11 游记 之 decltype constexpr
title: c++ 11 游记 1 keyword :c++ 11 decltype constexpr 作者:titer1 zhangyu 出处:www.drysaltery.com 联系:130 ...
- 轻量级分布式文件系统FastDFS使用安装说明手册(新手入门级)
轻量级分布式文件系统FastDFS使用安装说明手册(新手入门级) 实验室所在的课题组以研究云计算为主,但所有的研究都是在基于理论的凭空想像,缺少分布式环境的平台的实践,云计算神马的都是浮云了.因此,我 ...
- iOS开发技巧 - 使用UISegmentedControl来对信息进行分组
(Swift) import UIKit class ViewController: UIViewController { var segmentedControl:UISegmentedContro ...
- iOS编程(双语版)-视图-Autolayout代码初步
一谈到Autolayout,初学者肯定想到的是IB中使用拖拽啊,pin啊各种鼠标操作来进行添加各种约束. 今天我们要聊得是如何利用代码来添加视图间的约束. 我们来看一个例子: (Objective-C ...
- JavaScript Array 对象扩展方法
/** 删除数组中指定索引的数据 **/ Array.prototype.deleteAt = function (index) { if (index < 0) { return this; ...
- javascrip与C#高级语言的程序设计
javascript特点:解释型的.基于对象的脚本语言一.简单性:变量类型是采用弱类型,并未使用严格的数据类型.二.动态性:基于事件驱动三.跨平台性:依赖于浏览器本身,与操作环境无关.四.安全性:不允 ...
- Android versionCode和versionName的区别
简单的说,versionCode是给机器看的,versionName是给人看的.更新的时候,机器根据versionCode判断是升级还是降级,即使versionName(版本号)比以前的高,但是ver ...
- Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'系列二:reset slave
reset slave会清除从库的所有复制信息.一般应用场景:如切换为不同的Master, 主从重做等: 1. 命令在slave上执行,执行前一定要stop slave. 2. 执行reset sla ...
- Maven让资源文件处理插件能够解析资源文件中的Maven属性
<build> <resources> <resource> <directory>${project.basedir}/src/main/resour ...
- python必须要安装的库
1.requests 2.lxml 3.Django 4.BeautifulSoup 5.PyMySQL-0.7.0 (适用于python3) 6.图片处理PIL