一身转战三千里,一剑曾当百万师。这篇文章主要讲述Android自定义控件练手——波浪效果相关的知识,希望能为你提供帮助。
这一次要绘制出波浪效果,也是小白的我第一次还望轻喷。首先当然是展示效果图啦:
文章图片
一.首先来说说实现思路。
想到波浪效果,当然我第一反应是用正余弦波来设计啦(也能通过贝塞尔曲线,这里我不提及这个方法但是在demo里这种方法也实现了),肯定要绘制一个静态的波,然后通过不断的对它平移刷新,这样最简单的波浪效果就有了,如果再给它加一个比它提前一定周期的波一起平移,那不是波浪效果的层次就有了。
二.绘制。
首先要绘制一个静态的波形图,嗨呀说来简单但是怎么画呢,不要慌先看下面这张丑图:
文章图片
【Android自定义控件练手——波浪效果】 通过上面的图我们发现曲线被切分成了无数的竖线,我们可以知道波浪的高低,就是波峰与波谷,根据函数公式,通过不断的绘制竖线,就能得到一个静态波形图。代码如下:
1//在宽度以内绘制一条条竖线 2while (drawPoint.x < mWidth) { 3//第一条波的y坐标 4drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum)); 5canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint); 6//跳到下一个点继续 7drawPoint.x++; 8}
这里我们要注意绘制的默认坐标系如下图:
文章图片
画出静态的波形图之后,我们只要每次让这个波向前或者向后移动一定周期再不断刷新,就能出现波浪效果了。重写view的ondraw方法就有如下:
1 drawPoint.x = 0; //重置为0,从原点开始绘制 2Double rightperiod = Math.PI / 8 * count; //每次平移Math.PI/8个周期 3if (count == 16) {//每次平移Math.PI/8个周期,平移第16次,平移了一个完整的周期 4count = 0; //平移了一个完整周期归零重新开始计数 5} else { 6count++; 7} 8 9//在宽度以内绘制一条条竖线 10while (drawPoint.x < mWidth) { 11//第一条波的y坐标 12drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod)); 13//绘制最上面显示主波的竖线 14canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint); 15//跳到下一个点继续 16drawPoint.x++; 17} 18//定时更新 19postInvalidateDelayed(17);
这样一条会动的波浪就基本完成了,主体功能基本实现,之后再另外画一个平移一定周期的波浪并且通过用属性动画ValueAnimator对波浪波峰波谷与水位变化的调控就能达到上面的效果。下面是完整的代码:
文章图片
文章图片
1 public class WaveFunctionView extends View { 2private Path mPath; //路径 3private Paint mPaint, mPaintMore; //画笔 4private PointF drawPoint, drawPoint2; //绘制点 5private ValueAnimator animator, animatorh; 6private float mWidth, mHeight, waveHeight; //控件宽,控件高,水位 7private float waveDeepmin = 8f; //最小的波峰与波谷 8private float waveDeepMax = 20f; //最大的波峰与波谷 9private float waveDeep = 8f; //波峰与波谷 10private float arcRa = 0; //圆半径 11private Boolean iscircle = true; //是否是圆形图案 12private Boolean antiAlias = true; //是否开启抗锯齿 13public String MAINCOLOR_DEF = "#0000AA", NEXTCOLOR_DEF = "#0000FF"; //默认颜色 14private int mainColor = Color.parseColor(MAINCOLOR_DEF), nextColor = Color.parseColor(NEXTCOLOR_DEF); //颜色 15private Double anglenum = Math.PI / 180; 16private int count = 0; //绘制次数 17 18public WaveFunctionView(Context context) { 19super(context); 20init(); 21} 22 23public WaveFunctionView(Context context, AttributeSet attrs, int defStyleAttr) { 24super(context, attrs, defStyleAttr); 25init(); 26} 27 28public WaveFunctionView(Context context, AttributeSet attrs) { 29super(context, attrs); 30init(); 31} 32 33@Override 34protected void onSizeChanged(int w, int h, int oldw, int oldh) { 35mWidth = w; //获得控件宽度 36mHeight = h; //获得控件高度 37if (mWidth > mHeight) {//若要裁剪为圆形,以最短的长度为直径 38arcRa = mHeight / 2; 39if (iscircle) { 40mWidth = mHeight; 41} 42} else { 43arcRa = mWidth / 2; 44if (iscircle) { 45mHeight = mWidth; 46} 47} 48waveHeight = mHeight; //初始化开始水位 49ChangeWaveLevel(5); 50super.onSizeChanged(w, h, oldw, oldh); 51} 52 53//是否是圆形 54public void isCircle(Boolean iscircle) { 55this.iscircle = iscircle; 56} 57 58//是否开启抗锯齿 59public void setAntiAlias(Boolean antiAlias) { 60this.antiAlias = antiAlias; 61mPaint.setAntiAlias(antiAlias); 62mPaintMore.setAntiAlias(antiAlias); 63} 64 65//设置主波颜色 66public void setMainWaveColor(int color) { 67mainColor = color; 68mPaint.setColor(color); 69} 70 71//设置被遮挡的副波颜色 72public void setSecondaryWaveColor(int color) { 73nextColor = color; 74mPaintMore.setColor(color); 75} 76 77@Override 78protected void onDraw(Canvas canvas) { 79// TODO Auto-generated method stub 80super.onDraw(canvas); 81if (iscircle) {//判断是否定义为圆形 82mPath.reset(); //重置路径 83mPath.addCircle(arcRa, arcRa, arcRa, Path.Direction.CW); //画以(arcRa,arcRa),半径为arcRa的顺时针的圆 84canvas.clipPath(mPath); //裁剪 85} 86drawPoint.x = 0; //重置为0,从原点开始绘制 87Double rightperiod = Math.PI / 8 * count; //每次平移Math.PI/8个周期 88if (count == 16) {//每次平移Math.PI/8个周期,平移第16次,平移了一个完整的周期 89count = 0; //平移了一个完整周期归零重新开始计数 90} else { 91count++; 92} 93 94//在宽度以内绘制一条条竖线 95while (drawPoint.x < mWidth) { 96//第一条波的y坐标 97drawPoint.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod)); 98//第二条波的y坐标,比第一条向右移动了Math.PI/2个周期 99drawPoint2.y = (float) (waveHeight - waveDeep * Math.sin(drawPoint.x * anglenum - rightperiod - Math.PI / 2)); 100//先绘制被遮挡的副波的竖线 101canvas.drawLine(drawPoint.x, drawPoint2.y, drawPoint.x, mHeight, mPaintMore); 102//绘制最上面显示主波的竖线 103canvas.drawLine(drawPoint.x, drawPoint.y, drawPoint.x, mHeight, mPaint); 104//跳到下一个点继续 105drawPoint.x++; 106} 107//定时更新 108postInvalidateDelayed(17); 109} 110 111private void init() { 112mPath = new Path(); 113mPaint = new Paint(); 114mPaint.setColor(mainColor); //设置颜色 115mPaint.setAntiAlias(antiAlias); //抗锯齿(性能影响) 116mPaint.setStyle(Paint.Style.FILL); 117mPaint.setAlpha(50); 118mPaintMore = new Paint(); 119mPaintMore.setAntiAlias(antiAlias); //抗锯齿 120mPaintMore.setStyle(Paint.Style.FILL); 121mPaintMore.setColor(nextColor); //设置颜色 122mPaintMore.setAlpha(30); 123drawPoint = new PointF(0, 0); 124drawPoint2 = new PointF(0, 0); 125} 126 127public void ChangeWaveLevel(int percent) { 128animator = ValueAnimator.ofFloat(waveDeepmin, waveDeepMax); //设置属性值变化范围,最大波峰波谷与最小 129animator.setDuration(1000); //设置动画时间 130animator.setInterpolator(new LinearInterpolator()); //控制动画的变化速率 131animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 132@Override 133public void onAnimationUpdate(ValueAnimator animation) { 134waveDeep = (float) animation.getAnimatedValue(); 135} 136}); 137animator.setRepeatMode(ValueAnimator.REVERSE); //往返模式 138animator.setRepeatCount(1); 139animatorh = ValueAnimator.ofFloat(waveHeight, mHeight * (10 - percent) / 10); //水位变化 140animatorh.setDuration(2000); //设置动画时间 141animatorh.setInterpolator(new DecelerateInterpolator()); //控制动画的变化速率 142 143animatorh.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 144@Override 145public void onAnimationUpdate(ValueAnimator animation) { 146waveHeight = (float) animation.getAnimatedValue(); 147} 148}); 149animator.start(); //开始动画 150animatorh.start(); //开始动画 151} 152 }
完整代码
GitHub:https://github.com/SteinsGateZero/Mybeisaierwavetest.git
虽然简单,但是推荐还是得自己动手做一做。
推荐阅读
- Testin实验室(陌陌APP通过率为94.92% 基本满足移动社交需求)
- Android项目实战(四十)(在线生成按钮Shape的网站)
- 纯净版xp系统安装虚拟机里面后连不上网怎样办
- win xp系统下打开不了pps文件怎样办|xp系统下打开pps文件的办法
- XP系统多了lpk.dll文件怎样办|XP系统查杀lpk.dll病毒的办法
- XP系统打开不了DAT格式文件怎样办|XP系统打开DAT格式文件的办法
- 纯净版xp系统如何隐藏回收站图标|XP系统隐藏回收站图标的办法
- xp系统纯净版提示“已完毕 但页面上有出错”如何处理
- win xp系统下更改word默认字体的办法