Android自定义控件练手——波浪效果
这一次要绘制出波浪效果,也是小白的我第一次还望轻喷。首先当然是展示效果图啦:
一.首先来说说实现思路。
想到波浪效果,当然我第一反应是用正余弦波来设计啦(也能通过贝塞尔曲线,这里我不提及这个方法但是在demo里这种方法也实现了),肯定要绘制一个静态的波,然后通过不断的对它平移刷新,这样最简单的波浪效果就有了,如果再给它加一个比它提前一定周期的波一起平移,那不是波浪效果的层次就有了。
二.绘制。
首先要绘制一个静态的波形图,嗨呀说来简单但是怎么画呢,不要慌先看下面这张丑图:
通过上面的图我们发现曲线被切分成了无数的竖线,我们可以知道波浪的高低,就是波峰与波谷,根据函数公式,通过不断的绘制竖线,就能得到一个静态波形图。代码如下:
//在宽度以内绘制一条条竖线
while (drawPoint.x < mWidth) {
//第一条波的y坐标
drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum));
canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint);
//跳到下一个点继续
drawPoint.x++;
}
这里我们要注意绘制的默认坐标系如下图:
画出静态的波形图之后,我们只要每次让这个波向前或者向后移动一定周期再不断刷新,就能出现波浪效果了。重写view的ondraw方法就有如下:
drawPoint.x = 0;//重置为0,从原点开始绘制
Double rightperiod = Math.PI / 8 * count;//每次平移Math.PI/8个周期
if (count == 16) {//每次平移Math.PI/8个周期,平移第16次,平移了一个完整的周期
count = 0;//平移了一个完整周期归零重新开始计数
} else {
count++;
} //在宽度以内绘制一条条竖线
while (drawPoint.x < mWidth) {
//第一条波的y坐标
drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod));
//绘制最上面显示主波的竖线
canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint);
//跳到下一个点继续
drawPoint.x++;
}
//定时更新
postInvalidateDelayed(17);
这样一条会动的波浪就基本完成了,主体功能基本实现,之后再另外画一个平移一定周期的波浪并且通过用属性动画ValueAnimator对波浪波峰波谷与水位变化的调控就能达到上面的效果。下面是完整的代码:
public class WaveFunctionView extends View {
private Path mPath;//路径
private Paint mPaint, mPaintMore;//画笔
private PointF drawPoint, drawPoint2;//绘制点
private ValueAnimator animator, animatorh;
private float mWidth, mHeight, waveHeight;//控件宽,控件高,水位
private float waveDeepmin = 8f;//最小的波峰与波谷
private float waveDeepMax = 20f;//最大的波峰与波谷
private float waveDeep = 8f;//波峰与波谷
private float arcRa = 0;//圆半径
private Boolean iscircle = true;//是否是圆形图案
private Boolean antiAlias = true;//是否开启抗锯齿
public String MAINCOLOR_DEF = "#0000AA", NEXTCOLOR_DEF = "#0000FF";//默认颜色
private int mainColor = Color.parseColor(MAINCOLOR_DEF), nextColor = Color.parseColor(NEXTCOLOR_DEF);//颜色
private Double anglenum = Math.PI / 180;
private int count = 0;//绘制次数 public WaveFunctionView(Context context) {
super(context);
init();
} public WaveFunctionView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} public WaveFunctionView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w;//获得控件宽度
mHeight = h;//获得控件高度
if (mWidth > mHeight) {//若要裁剪为圆形,以最短的长度为直径
arcRa = mHeight / 2;
if (iscircle) {
mWidth = mHeight;
}
} else {
arcRa = mWidth / 2;
if (iscircle) {
mHeight = mWidth;
}
}
waveHeight = mHeight;//初始化开始水位
ChangeWaveLevel(5);
super.onSizeChanged(w, h, oldw, oldh);
} //是否是圆形
public void isCircle(Boolean iscircle) {
this.iscircle = iscircle;
} //是否开启抗锯齿
public void setAntiAlias(Boolean antiAlias) {
this.antiAlias = antiAlias;
mPaint.setAntiAlias(antiAlias);
mPaintMore.setAntiAlias(antiAlias);
} //设置主波颜色
public void setMainWaveColor(int color) {
mainColor = color;
mPaint.setColor(color);
} //设置被遮挡的副波颜色
public void setSecondaryWaveColor(int color) {
nextColor = color;
mPaintMore.setColor(color);
} @Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (iscircle) {//判断是否定义为圆形
mPath.reset();//重置路径
mPath.addCircle(arcRa, arcRa, arcRa, Path.Direction.CW);//画以(arcRa,arcRa),半径为arcRa的顺时针的圆
canvas.clipPath(mPath);//裁剪
}
drawPoint.x = 0;//重置为0,从原点开始绘制
Double rightperiod = Math.PI / 8 * count;//每次平移Math.PI/8个周期
if (count == 16) {//每次平移Math.PI/8个周期,平移第16次,平移了一个完整的周期
count = 0;//平移了一个完整周期归零重新开始计数
} else {
count++;
} //在宽度以内绘制一条条竖线
while (drawPoint.x < mWidth) {
//第一条波的y坐标
drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod));
//第二条波的y坐标,比第一条向右移动了Math.PI/2个周期
drawPoint2.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod - Math.PI / 2));
//先绘制被遮挡的副波的竖线
canvas.drawLine(drawPoint.x, drawPoint2.y, drawPoint.x, mHeight, mPaintMore);
//绘制最上面显示主波的竖线
canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint);
//跳到下一个点继续
drawPoint.x++;
}
//定时更新
postInvalidateDelayed(17);
} private void init() {
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(mainColor);//设置颜色
mPaint.setAntiAlias(antiAlias);//抗锯齿(性能影响)
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAlpha(50);
mPaintMore = new Paint();
mPaintMore.setAntiAlias(antiAlias);//抗锯齿
mPaintMore.setStyle(Paint.Style.FILL);
mPaintMore.setColor(nextColor);//设置颜色
mPaintMore.setAlpha(30);
drawPoint = new PointF(0, 0);
drawPoint2 = new PointF(0, 0);
} public void ChangeWaveLevel(int percent) {
animator = ValueAnimator.ofFloat(waveDeepmin, waveDeepMax);//设置属性值变化范围,最大波峰波谷与最小
animator.setDuration(1000);//设置动画时间
animator.setInterpolator(new LinearInterpolator());//控制动画的变化速率
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
waveDeep = (float) animation.getAnimatedValue();
}
});
animator.setRepeatMode(ValueAnimator.REVERSE);//往返模式
animator.setRepeatCount(1);
animatorh = ValueAnimator.ofFloat(waveHeight, mHeight * (10 - percent) / 10);//水位变化
animatorh.setDuration(2000);//设置动画时间
animatorh.setInterpolator(new DecelerateInterpolator());//控制动画的变化速率 animatorh.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
waveHeight = (float) animation.getAnimatedValue();
}
});
animator.start();//开始动画
animatorh.start();//开始动画
}
}
完整代码
GitHub:https://github.com/SteinsGateZero/Mybeisaierwavetest.git
虽然简单,但是推荐还是得自己动手做一做。
Android自定义控件练手——波浪效果的更多相关文章
- Android自定义控件练手——简单的时钟
首先这应该是一个老生常谈的设计了,但是毕竟身为小白的自己都没动手做过,不动手怎么提高自己呢,所以在这梅林沉船闲暇之际,我就把我的设计流程与思路记录下来.首先来看看效果图吧: 如上图就是一个简单并没有美 ...
- android自定义控件(5)-实现ViewPager效果
对于系统的ViewGroup我们已经是十分熟悉了,最常用的LinearLayout和RelativeLayout几乎是天天要打交道,下面我们就来看看,如何一步一步将其实现: 一.首先当然也是最通常的新 ...
- Android自定义控件实战——水流波动效果的实现WaveView
转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38556891 水流波动的波形都是三角波,曲线是正余弦曲线,但是Android ...
- Android自定义控件简单实现ratingbar效果
先上图: 一开始让我自定义控件我是拒绝的,因为android很早以前就有一个控件ratingbar,但是设置样式的时候我发现把图片设置小一点就显示不全,一直找不到解办法!(可以设置系统的自带的小样式) ...
- Android自定义控件-Path之贝赛尔曲线和手势轨迹、水波纹效果
从这篇开始,我将延续androidGraphics系列文章把图片相关的知识给大家讲完,这一篇先稍微进阶一下,给大家把<android Graphics(二):路径及文字>略去的quadTo ...
- android自定义控件(4)-自定义水波纹效果
一.实现单击出现水波纹单圈效果: 照例来说,还是一个自定义控件,观察这个效果,发现应该需要重写onTouchEvent和onDraw方法,通过在onTouchEvent中获取触摸的坐标,然后以这个坐标 ...
- Android 自定义控件实现刮刮卡效果 真的就只是刮刮卡么
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40162163 , 本文出自:[张鸿洋的博客] 很久以前也过一个html5的刮刮卡 ...
- jQuery练手:仿新浪微博图片文字列表淡进淡出上下滚动效果
1.效果及功能说明 仿新浪微博图片文字列表上下淡进淡出间歇上下滚动 2.实现原理 首先要设定div内只能显示4个图片那么多出来的图片会自动隐藏然后在给图片添加一个动画的事件让他们可以滚动的播放出来上下 ...
- Android自定义控件实战——滚动选择器PickerView
转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38513301 手机里设置闹钟需要选择时间,那个选择时间的控件就是滚动选择器, ...
随机推荐
- 微信网页授权操作逻辑封装-C#实例
http://blog.csdn.net/u011127019/article/details/52650619
- CF1076C Meme Problem 数学
Try guessing the statement from this picture: You are given a non-negative integer d . You have to f ...
- kuangbin专题十六 KMP&&扩展KMP HDU3746 Cyclic Nacklace
CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, ...
- spring中IOC容器注册和获取bean的实例
spring中常用的功能主要的是ioc和aop,此处主要说明下,实例注册和使用的方法,此为学习后的笔记记录总结 1.使用xml文件配置 在idea中创建maven工程,然后创建实例Person,然后在 ...
- php小试牛刀
[构造函数] function __construct() [析构函数] 当某个对象的所有引用被删除,或者对象被显式的销毁时会执行析构函数 function __destruct() [静态方法] p ...
- vue.js 基础
vuejs 遍历 数组, vue js 文章 http://www.cnblogs.com/libin-1/p/6851775.html https://zhuanlan.zhihu.com/p/ ...
- C#学习之按钮点击事件
描述:asp.net中服务器控件Button的点击事件OnClientClick和OnClick的区别? 解答:http://www.cnblogs.com/ypfnet/archive/2012/1 ...
- Python入门字符编码
计算机基础知识 一.应用程序任何操作硬件的请求都需要向操作系统发起系统调用,然后由操作系统去操作硬件 二.文本编辑器存取文件的原理 1.打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编 ...
- python中 列表 字典 元组的了解
#######列表######1.列表的特性 server = [['http'],['ssh'],['ftp']] server1 = [['mysql'],['firewalld']] 连接 ...
- vue2.0组件的生命周期
beforeCreate(){ console.log(new Date().getTime()) let data = this.text; console.log('组件创立之前') consol ...