博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义View合辑(6)-波浪(贝塞尔曲线)
阅读量:7023 次
发布时间:2019-06-28

本文共 2750 字,大约阅读时间需要 9 分钟。

为了加强对自定义 View 的认知以及开发能力,我计划这段时间陆续来完成几个难度从易到难的自定义 View,并简单的写几篇博客来进行介绍,所有的代码也都会开源,也希望读者能给个 star 哈 GitHub 地址: 也可以下载 Apk 来体验下:

先看下效果图:

一、思路解析

波浪 View(即 WaveView)的重点在于其 onDraw 方法的十行代码上,当中运用到了贝塞尔曲线的知识

//每个波浪的起伏高度    private float waveHeight;    //每个波浪的宽度    private float waveWidth;    //波浪的速度    private long speed = DEFAULT_SPEED;    private float animatedValue;    private Path path = new Path();    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        path.reset();        path.moveTo(-waveWidth + animatedValue, contentHeight / 2);        for (float i = -waveWidth; i < contentWidth + waveWidth; i += waveWidth) {            path.rQuadTo(waveWidth / 4, -waveHeight, waveWidth / 2, 0);            path.rQuadTo(waveWidth / 4, waveHeight, waveWidth / 2, 0);        }        path.lineTo(contentWidth, contentHeight);        path.lineTo(0, contentHeight);        path.close();        canvas.drawPath(path, paint);    }复制代码

从图片可以看出来各个波浪的起伏高度和宽度都是一样的,意味着在贝塞尔曲线中控制点的 Y 坐标是保持不变的,以上的逻辑可以利用下图来帮助理解

蓝色背景代表的是 View 所占的面积,红色小球连起来的曲线轨迹即为波浪的运行轨迹waveWidth 代表的是每个波浪的宽度,即每一个绿色方块的宽度。两个 path.rQuadTo 方法所绘制出来的分别是向上的曲线和向下的曲线,并在 for 循环中不断重复这个过程,直到绿色方块所占的总宽度超出 View 的宽度为止

为了呈现出**“波浪向右前进”的效果,当中就需要用到动画值 animatedValue 来不断改变贝塞尔曲线的起始坐标点**

private ValueAnimator valueAnimator;    public void initAnimation() {        valueAnimator = new ValueAnimator();        valueAnimator.setDuration(speed);        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);        valueAnimator.setInterpolator(new LinearInterpolator());        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                animatedValue = (float) animation.getAnimatedValue();                invalidate();            }        });    }复制代码

然后向外部开放改变波浪宽度、波浪高度、动画时长的这三个方法,即可以此来改变 View 的形状

public void setWaveScaleWidth(float waveScaleWidth) {        if (waveScaleWidth <= 0 || waveScaleWidth > 1) {            return;        }        this.waveScaleWidth = waveScaleWidth;        resetWaveParams();    }    public void setWaveScaleHeight(float waveScaleHeight) {        if (waveScaleWidth <= 0 || waveScaleWidth > 1) {            return;        }        this.waveScaleHeight = waveScaleHeight;        resetWaveParams();    }    public void setSpeed(long speed) {        this.speed = speed;        resetWaveParams();    }    private void resetWaveParams() {        waveWidth = contentWidth * waveScaleWidth;        waveHeight = contentHeight * waveScaleHeight;        if (valueAnimator != null) {            valueAnimator.setFloatValues(0, waveWidth);            valueAnimator.setDuration(speed);        }    }复制代码

转载于:https://juejin.im/post/5cd2f2d0518825556874040d

你可能感兴趣的文章
第十次作业
查看>>
AngularJS之WebAPi上传(十)
查看>>
数组的连续子数组最大和(首尾相连)
查看>>
《Programming in Lua 3》读书笔记(一)
查看>>
HTML元素的ID和Name属性的区别
查看>>
【Spring AOP 详解】
查看>>
字典树模板
查看>>
python基础练习-购物车
查看>>
poj 2406 && poj 1961 (KMP)
查看>>
Flutter: AnimatedCrossFade 在两个给定的子节点之间交叉淡化,避免大量三元表达式...
查看>>
iOS圆形图片裁剪,原型图片外面加一个圆环
查看>>
位运算
查看>>
Lucene:Query
查看>>
安卓文件的资源访问
查看>>
Java变量的作用域和生存期
查看>>
EXCEL IF 函数 模糊查询
查看>>
Angularjs 中的 controller
查看>>
ZigZag Conversion
查看>>
SQLLoader8(加载的数据中有换行符处理方法)
查看>>
表的创建、修改及约束
查看>>