1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Android自定义View——贝塞尔曲线实现水波纹进度球

Android自定义View——贝塞尔曲线实现水波纹进度球

时间:2019-12-28 19:23:22

相关推荐

Android自定义View——贝塞尔曲线实现水波纹进度球

效果图

原理分析

首先需要了解的水波纹实现效果,可以在博客的自定义View专题找到,其实现原理如下

利用贝塞尔曲线绘制屏幕外和屏幕内的sin曲线利用path将sin曲线的左下角和右下角连接起来成为一块区域通过不断的平移sin曲线,然后平移完一个周期则重新回到原点

实现步骤

绘制实现的步骤如下

裁剪画布为圆形绘制圆形边框绘制波浪区域绘制进度文字自动增长进度

1、初始化变量

public class WaveView extends View {//View的宽高private int width;private int height;//View的画笔private Paint wavePaint;private Paint textPaint;private Paint circlePaint;//波浪的路径private Path path;//sin曲线的长度:一个周期长度private int cycle = 160;//每次平移的长度,为四分之一个周期private int translateX = cycle / 4;//sin曲线振幅的高度private int waveHeight = 80;//sin曲线的起点坐标private Point startPoint;//当前波浪的进度private int progress = 0;//当前波浪的速度private int waveSpeech = 150;//是否启用了自动增长进度private boolean isAutoIncrease = false;public WaveView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);initPaint(context);}public WaveView(Context context) {super(context);initPaint(context);}private void initPaint(Context context) {path = new Path();wavePaint = new Paint();wavePaint.setAntiAlias(true);wavePaint.setStyle(Paint.Style.FILL);wavePaint.setColor(Color.parseColor("#1998FA"));circlePaint = new Paint();circlePaint.setStrokeWidth(5);circlePaint.setStyle(Paint.Style.STROKE);circlePaint.setAntiAlias(true);circlePaint.setColor(Color.parseColor("#1998FA"));textPaint = new Paint();textPaint.setAntiAlias(true);textPaint.setTextSize(50);textPaint.setColor(Color.BLUE);}}

2、获取宽和高

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//由于是一个圆形,所以取的值是宽高的最小值width = measureSize(400, widthMeasureSpec);height = measureSize(400, heightMeasureSpec);width = Math.min(width, height);height = Math.min(width, height);setMeasuredDimension(width, height);//初始化起点,为屏幕外的一个周期startPoint = new Point(-cycle * 4, 0);}/*** 测量宽高** @param defaultSize* @param measureSpec* @return*/private int measureSize(int defaultSize, int measureSpec) {int result = defaultSize;int mode = MeasureSpec.getMode(measureSpec);int size = MeasureSpec.getSize(measureSpec);switch (mode) {case MeasureSpec.UNSPECIFIED:result = defaultSize;break;case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = size;break;}return result;}

3、绘制图形

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//设置内间距setPadding(20, 20, 20, 20);//裁剪画布为圆形clipCicle(canvas);//绘制圆形边框drawCicleBorder(canvas);//绘制波浪区域drawWavePath(canvas);//绘制进度文字drawProcessText(canvas);//自动增长进度if (isAutoIncrease) {if (progress >= 100) {progress = 0;} else {progress++;}}//更新UIpostInvalidateDelayed(waveSpeech);}/*** 裁剪画布为圆形* * @param canvas*/private void clipCicle(Canvas canvas) {Path circlePath = new Path();circlePath.addCircle(width / 2, height / 2, width / 2, Path.Direction.CW);canvas.clipPath(circlePath);}/*** 绘制圆形边框** @param canvas*/private void drawCicleBorder(Canvas canvas) {canvas.drawPaint(circlePaint);canvas.drawCircle(width / 2, height / 2, width / 2, circlePaint);}/*** 绘制波浪区域** @param canvas*/private void drawWavePath(Canvas canvas) {//根据进度改变起点坐标的y值startPoint.y = (int) ((1 - (progress / 100.0)) * (height / 2 + width / 2));Log.e("TAG", "startPoint.y:" + startPoint.y);//移动区域起点path.moveTo(startPoint.x, startPoint.y);int j = 1;//循环绘制正弦曲线区域,循环两个周期for (int i = 1; i <= 8; i++) {if (i % 2 == 0) {//波峰path.quadTo(startPoint.x + (cycle * j), startPoint.y + waveHeight,startPoint.x + (cycle * 2) * i, startPoint.y);} else {//波谷path.quadTo(startPoint.x + (cycle * j), startPoint.y - waveHeight,startPoint.x + (cycle * 2) * i, startPoint.y);}j += 2;}//绘制封闭的区域path.lineTo(width, height);//右下角path.lineTo(startPoint.x, height);//左下角path.lineTo(startPoint.x, startPoint.y);//起点path.close();//绘制区域canvas.drawPath(path, wavePaint);path.reset();//一开始的起点是在-160,160 = 40 + 40 + 40 + 40,走完一个周期则回到原点if (startPoint.x + translateX >= 0) {startPoint.x = -cycle * 4;} else {startPoint.x += translateX;}}/*** 绘制进度文字** @param canvas*/private void drawProcessText(Canvas canvas) {//画布的大小Rect targetRect = new Rect(0, 0, width, height);Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;// 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()textPaint.setTextAlign(Paint.Align.CENTER);canvas.drawText(progress + "%", targetRect.centerX(), baseline, textPaint);}

4、提供对外API

/*** 开启自动增长*/public void startIncrease() {isAutoIncrease = true;invalidate();}/*** 设置当前进度** @param progress 进度*/public void setProgress(int progress) {if (progress > 100 || progress < 0)throw new RuntimeException(getClass().getName() + "请设置[0,100]之间的值");this.progress = progress;invalidate();}/*** 通过动画设置当前进度** @param targetProcess 进度 <=100* @param duration动画时长*/public void setProgress(final int targetProcess, int duration) {if (progress > 100 || progress < 0)throw new RuntimeException(getClass().getName() + "请设置[0,100]之间的值");ValueAnimator progressAnimator = ValueAnimator.ofInt(progress, targetProcess);progressAnimator.setDuration(duration);progressAnimator.setTarget(progress);progressAnimator.setInterpolator(new LinearInterpolator());progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {setProgress((Integer) animation.getAnimatedValue());}});progressAnimator.start();}/*** 获取当前进度** @return*/public int getProgress() {return progress;}

5、使用API

public class WaterWaveActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_water_wave);// API三选一即可// 设置当前进度条((WaveView) findViewById(R.id.wv)).setProgress(50);// 在10秒钟内将进度条增长到50%((WaveView) findViewById(R.id.wv)).setProgress(50, 10000);// 自动增长进度从0到100((WaveView) findViewById(R.id.wv)).startIncrease();}}

6、源码下载

水波纹进度球View下载

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。