先来看一下这次要实现的最终效果:

首先来实现效果一,为实现效果二做充足的准备,下面开始:

新建工程,并定义一个自定义View,然后将其定义在布局文件中,里面是空实现,之后会一步步来填充代码:

MyRing.java:

public class MyRing extends View {

    public MyRing(Context context, AttributeSet attrs) {
super(context, attrs);
} }

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" > <com.example.waveview.MyRing
android:layout_width="match_parent"
android:layout_height="match_parent"
/> </RelativeLayout>

接下来一步步来实现第一张效果图所示的效果,先重写父类的某些方法:

public class MyRing extends View {

    public MyRing(Context context, AttributeSet attrs) {
super(context, attrs);
} /**
* 大小的测量按系统的默认规则
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /**
* 绘制我们的内容
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}

在点击时需要画一个圆,这是第一步,所以需要监听触摸事件:

public class MyRing extends View {

    /**
* 圆环圆心的X坐标
*/
private int cx; /**
* 圆环圆心的Y坐标
*/
private int cy;
private Paint paint;
/**
* 线条的厚度
*/
private float strokeWidth; public MyRing(Context context, AttributeSet attrs) {
super(context, attrs);
// 初始化paint
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStyle(Style.STROKE); // 刻画,画线条
paint.setStrokeWidth(strokeWidth); // 设置条线的厚度
} /**
* 大小的测量按系统的默认规则
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /**
* 绘制我们的内容
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 绘制圆环,为了看到效果先将半径写死
*/
canvas.drawCircle(cx, cy, 100, paint);
} @Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: // 点击,获得圆环的中心
cx = (int) event.getX();
cy = (int) event.getY();
invalidate();
break;
}
return true;
}
}

效果如下:

默认圆画在(0,0)的位置,有了第一步之后,接下来则要让这个圆进行动态渐变,半径、圆边线的粗度都得动态去改变,具体代码如下:

public class MyRing extends View {

    /**
* 圆环圆心的X坐标
*/
private int cx; /**
* 圆环圆心的Y坐标
*/
private int cy;
private Paint paint;
/**
* 线条的厚度
*/
private float strokeWidth;
/**
* 圆环的半径
*/
private float radius;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
flushState();
// 刷新页面 执行onDraw()方法
invalidate();
if (paint.getAlpha() != 0) {
handler.sendEmptyMessageDelayed(0, 100);
}
};
}; public MyRing(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
} private void initView() {
// 初始化paint
paint = new Paint();
paint.setAntiAlias(true); // 抗矩齿
paint.setColor(Color.RED);
paint.setStyle(Style.STROKE); // 刻画,画线条
paint.setStrokeWidth(strokeWidth); // 设置条线的厚度
paint.setAlpha(255); // 设置透明度 ,0--255 0代表完全透明 //
this.radius = 0;
strokeWidth = 0;
} /**
* 大小的测量按系统的默认规则
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /**
* 绘制我们的内容
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 绘制圆环
*/
canvas.drawCircle(cx, cy, radius, paint);
} @Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: // 点击,获得圆环的中心
cx = (int) event.getX();
cy = (int) event.getY();
// 初始化画笔
initView();
handler.sendEmptyMessage(0);
break;
}
return true;
} /*
* 刷新状态
*/
private void flushState() {
this.radius += 10;
this.strokeWidth = radius / 4;
paint.setStrokeWidth(strokeWidth); int nextAlpha = paint.getAlpha() - 20;
if (nextAlpha <= 20) {
nextAlpha = 0;
}
paint.setAlpha(nextAlpha); }
}

这时就是图一的效果了,有了这个基础,要实现图二的效果也就不难了,下面来试一下:

由于是多个圆,所以肯定是需要一个集合来存储,另外需要用一个实体来表示一个圆的多个属性,如下:

    /**
* 定义一个波浪
* @author leo
*/
private class Wave {
//圆心
int cx;
int cy; //画笔
Paint p;
//半径
int r;
}

然后在按下或滑动时,则把相应的点给添加到集合中,并且需要点与点之间有一定的距离才行,挨得太近则不添加,具体逻辑如下:

    @Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: int x = (int) event.getX();
int y = (int) event.getY(); addPoint(x,y); break; default:
break;
} return true; }

而添加的方法如下:

/**
* 添加新的波浪中心点
* @param x
* @param y
*/
private void addPoint(int x, int y) {
if(wList.size() == 0){
addPoint2List(x,y);
/*
* 第一次启动动画
*/
isRunning = true;
handler.sendEmptyMessage(0);
}else{
Wave w = wList.get(wList.size()-1); if(Math.abs(w.cx - x)>DIS_SOLP || Math.abs(w.cy-y)>DIS_SOLP){
addPoint2List(x,y);
} }; } /**
* 添加新的波浪
* @param x
* @param y
*/
private void addPoint2List(int x, int y) {
Wave w = new Wave();
w.cx = x;
w.cy=y;
Paint pa=new Paint();
pa.setColor(colors[(int)(Math.random()*4)]);
pa.setAntiAlias(true);
pa.setStyle(Style.STROKE); w.p = pa; wList.add(w);
}

其中当一第一次添加时,则会开启handler去跑圆环动画,其它的则相继往集合中添加,而handler的写法跟一个圆环的写法差不多,这里就不多解释,直接把整个代码贴上来,都比较好理解:

/**
* 水波纹效果
*
*/
public class MyRingWave extends View{ /**
* 二个相临波浪中心点的最小距离
*/
private static final int DIS_SOLP = 13; protected boolean isRunning = false; private ArrayList<Wave> wList; public MyRingWave(Context context, AttributeSet attrs) {
super(context, attrs);
wList = new ArrayList<MyRingWave.Wave>();
} private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) { //刷新数据
flushData();
//刷新页面
invalidate();
//循环动画
if (isRunning) {
handler.sendEmptyMessageDelayed(0, 50);
} };
}; @Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < wList.size(); i++) {
Wave wave = wList.get(i);
canvas.drawCircle(wave.cx, wave.cy, wave.r, wave.p);
}
} @Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: int x = (int) event.getX();
int y = (int) event.getY(); addPoint(x,y); break; default:
break;
} return true; } /**
* 添加新的波浪中心点
* @param x
* @param y
*/
private void addPoint(int x, int y) {
if(wList.size() == 0){
addPoint2List(x,y);
/*
* 第一次启动动画
*/
isRunning = true;
handler.sendEmptyMessage(0);
}else{
Wave w = wList.get(wList.size()-1); if(Math.abs(w.cx - x)>DIS_SOLP || Math.abs(w.cy-y)>DIS_SOLP){
addPoint2List(x,y);
} }; } /**
* 添加新的波浪
* @param x
* @param y
*/
private void addPoint2List(int x, int y) {
Wave w = new Wave();
w.cx = x;
w.cy=y;
Paint pa=new Paint();
pa.setColor(colors[(int)(Math.random()*4)]);
pa.setAntiAlias(true);
pa.setStyle(Style.STROKE); w.p = pa; wList.add(w);
} private int [] colors = new int[]{Color.BLUE,Color.RED,Color.YELLOW,Color.GREEN};
/**
* 刷新数据
*/
private void flushData() { for (int i = 0; i < wList.size(); i++) { Wave w = wList.get(i); //如果透明度为 0 从集合中删除
int alpha = w.p.getAlpha();
if(alpha == 0){
wList.remove(i); //删除i 以后,i的值应该再减1 否则会漏掉一个对象,不过,在此处影响不大,效果上看不出来。
continue;
} alpha-=5;
if(alpha<5){
alpha =0;
}
//降低透明度
w.p.setAlpha(alpha); //扩大半径
w.r = w.r+3;
//设置半径厚度
w.p.setStrokeWidth(w.r/3);
} /*
* 如果集合被清空,就停止刷新动画
*/
if(wList.size() == 0){
isRunning = false;
}
} /**
* 定义一个波浪
* @author leo
*/
private class Wave {
//圆心
int cx;
int cy; //画笔
Paint p;
//半径
int r;
}
}

对于这个自定义效果倒不是很复杂,但效果还是挺炫滴,以后坚持收集学习好的UI效果。

自定义View-----汽泡效果的更多相关文章

  1. android自定义view实现公章效果

    上次去一个公司面试,面试官问了一个题,怎么用android的自定义view实现一个公章的效果,据说这是华为之前的面试题,我想了下,要是公章的效果,最外层是一个圆,里面是一个五角星,但是这文字怎么画呢, ...

  2. 自定义View实现钟摆效果进度条PendulumView

    转载请注明出处:http://blog.csdn.net/fightlei/article/details/52556755 在网上看到了一个IOS组件PendulumView,实现了钟摆的动画效果. ...

  3. Android 自定义View跑马灯效果(一)

    今天通过书籍重新复习了一遍自定义VIew,为了加强自己的学习,我把它写在博客里面,有兴趣的可以看一下,相互学习共同进步: 通过自定义一个跑马灯效果,来诠释一下简单的效果: 一.创建一个类继承View, ...

  4. android 自定义view之侧滑效果

    效果图: 看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来.但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的. 知识点: 1.Vi ...

  5. HTML5 汽泡效果

    又到了晚上了,精神只有在晚上的时候才能爆发,可能程序员的命吧.废话就不多说了,今天我为大家带来的是一个气泡的效果.  代码下载 下面请看效果图

  6. 在RecyclerView中集成QQ汽泡二

    上次已经将GooView集成到RecyclerView当中了[http://www.cnblogs.com/webor2006/p/7787511.html],但是目前还有很多问题,下面先来运行看一下 ...

  7. 在RecyclerView中集成QQ汽泡一

    上次已经实现了QQ汽泡的自定义View的效果[http://www.cnblogs.com/webor2006/p/7726174.html],接着再将它应用到列表当中,这样才算得上跟QQ的效果匹配, ...

  8. 分析自定义view的实现过程-实现雪花飞舞效果(转载有改动)

    声明:本文源码出自实现雪花飞舞效果(有改动)主要通过这篇文来分析自定义view的实现过程. 没事时,比较喜欢上网看看一些新的东西,泡在网上的日子就是一个很不错的网站. 下面开始了,哈哈.^_^ 大家都 ...

  9. Android自定义View之圆环交替 等待效果

    学习了前面两篇的知识,对于本篇实现的效果,相信大家都不会感觉太困难,我要实现的效果是什么样呢?下面请先看效果图: 看上去是不很炫的样子,它的实现上也不是很复杂,重点在与onDraw()方法的绘制. 首 ...

  10. Android自定义View 画弧形,文字,并增加动画效果

    一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类   B ...

随机推荐

  1. 移动架构-UML

    UML(Unified Modeling Language),UML规范用来描述建模的概念有,类(对象的).对象.关联.职责.行为.接口.用例.包.顺序.协作,以及状态.这里对UML做一个简单介绍 前 ...

  2. java如何获取当前日期和时间

    System.currentTimeMillis() 获取标准时间可以通过System.currentTimeMillis()方法获取,此方法不受时区影响,得到的结果是时间戳格式的.例如: 15431 ...

  3. springboot与shiro在html中使用shiro标签

    上一章讲环境搭建 springboot与shiro和mybatis和mysql 现在讲html中怎么使用shiro标签,这里是基于上一章讲的 在pom文件引入依赖 <dependency> ...

  4. 【51nod】1634 刚体图

    [51nod]1634 刚体图 给一个左边n个点右边m个点二分图求合法的连通图个数,每条边选了之后会带来价值乘2的贡献 类似城市规划那道题的计数 设\(g[i][j]\)为左边\(i\)个点,右边\( ...

  5. Feign【token传递】

    使用feign调用服务的时候,存在一个问题,比如当前服务调用A服务,在请求头中包含了某些特殊的字段信息,比如当前操作人的token信息,调用A的时候可以正常拿到token,然而在去调用B服务的时候,可 ...

  6. C++中const关键字用法总结

    看完了c++ primer的基础篇,对const还是有点陌生,在这里小小地总结一下吧. 1) const与变量 在变量的定义前加上 const 修饰符即可完成const对象的创建. const int ...

  7. Centos7.3安装,并设置网络和防火墙

    下载centos7.3安装ISO 最小化安装,随后打通网络,完成网络设置.安装VIM,关闭firewalld防火墙,打开iptables防火墙 重启, vim /etc/sysconfig/netwo ...

  8. js 颜色随机切换

    生成随机颜色 方法1:RGB模式 function randomColor1() { var r=Math.floor(Math.random()*256); var g=Math.floor(Mat ...

  9. html如何点击子元素事件而不触发父元素的点击事件——阻止冒泡

    如果子元素和父元素都有点击事件,会出现点击事件冒泡的情况. 1.如何避免冒泡: html: <html> <head></head> <body> &l ...

  10. 总结一下C++与C#之间的区别

    1,C#不支持多重继承 2.在标准的C#安全代码中不支持指针类型的操作,然而,你却能在微软所谓的“非安全代码”中操作指针类型对象. 3.C#中所有对象都只能通过关键词“new”来创建,C++的“类名_ ...