能量球效果(贝塞尔曲线)
来源:互联网 发布:快手特效视频软件 编辑:程序博客网 时间:2024/06/05 10:35
在项目中需要用能量球来展示活动余额的剩余量,如下图的效果:
看到效果图,首先就会想怎么实现这个波浪的效果,其实这就是两个波浪线一直在左右移动,然后给你一个一直在那浪啊浪的错觉~~~说到曲线,脑阔中第一个蹦出来的就是贝塞尔曲线。要用贝塞尔曲线,首先还是要确定控制点,先看一张图(没有好的作图工具,凑合着看了- -!):
如上图,一个完整的波要这5个点来确定,其中B和D点就是控制点,像我这个是将view的宽度均分成4段,这些点的坐标很容易算出来了。
下面贴出画波的主要代码:
private float waveHeightPercent = 0.7f; //波的高度百分比 private float waveTranslateValue = 0f; //波水平移动的比例 private float waveAmplitude; //波的振幅 private int waveCount = 4; //波的数量 //这边是为了保证view为正方形,方便后面圆形好弄 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int minSize = Math.min(widthSize, heightSize); setMeasuredDimension(minSize, minSize); } protected void onDraw(Canvas canvas) { float levelHeight = (1 - waveHeightPercent) * height; //波实际高度 float specWidth = width/waveCount; //四分之一波长 float translateX = width * waveTranslateValue; //水平移动的实际距离 //这两个方法是计算波形路径 setFrontWavePath(levelHeight, specWidth, translateX); setBehindWavePath(levelHeight, specWidth, translateX); //画后面的波 wavePaint.setColor(ContextCompat.getColor(context, R.color.behind_color)); canvas.drawPath(wavePathBehind, wavePaint); //画前面的波 wavePaint.setColor(ContextCompat.getColor(context, R.color.front_color)); canvas.drawPath(wavePathFront, wavePaint); }
下面只贴出setFrontWavePath()这个方法,setBehindWavePath()和它类似,只不过波的方向是反过来的:
private void setFrontWavePath(float levelHeight, float specWidth, float translateX){ wavePathFront.reset(); wavePathFront.moveTo(0 - translateX, height); wavePathFront.lineTo(0 - translateX, levelHeight); for(int i=1;i<=waveCount;i++){ float controlX = specWidth * (i*2 - 1) - translateX; float controlY = i%2 != 0 ? levelHeight - waveAmplitude : levelHeight + waveAmplitude; float toX = specWidth * (2 * i) - translateX; wavePathFront.quadTo(controlX, controlY, toX, levelHeight); } wavePathFront.lineTo(specWidth * waveCount + translateX, height); wavePathFront.close(); }
这边画波浪,用的二阶贝塞尔曲线,最后路径闭合,是为了填充颜色。
现在运行一下,基础波形就出来了,入下图:
接下来就是加入动画效果,让波来回移动,代码如下:
public void waveAnimate(){ ObjectAnimator transAnim = ObjectAnimator.ofFloat(this, "waveTranslateValue", 0, 1); transAnim.setInterpolator(new LinearInterpolator()); transAnim.setDuration(1000); transAnim.setRepeatCount(ValueAnimator.INFINITE); ObjectAnimator upAnim = ObjectAnimator.ofFloat(this, "waveHeightPercent", 0, waveHeightPercent); upAnim.setDuration(3000); animatorSet.playTogether(transAnim, upAnim); animatorSet.start(); }
这边用属性动画来完成波的移动,waveTranslateValue这个属性,控制波的水平移动;waveHeightPercent属性,控制波的高度,现在来看下效果:
到这里,剩下最后一个就是把矩形变成圆形,这边首先想到的就是裁剪画布,那就直接写上代码如下:
clipPath.addCircle(circleX, circleY, circleRadius, Path.Direction.CW);canvas.clipPath(clipPath);
圆的坐标和半径根据view的宽高很容易得到,然后在onDraw中调用canvas.clipPath(clipPath),实际效果如下:
从图中看到,圆有锯齿,裁剪没有用到Paint类,不好设置抗锯齿,所以效果不是很好。
下面用Paint 的Xfermode模式来修改一下,代码如下:
//初始化Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); protected void onDraw(Canvas canvas) { float levelHeight = (1 - waveHeightPercent) * height; float specWidth = width/waveCount; float translateX = width * waveTranslateValue; canvas.drawCircle(circleX, circleY, circleRadius, bgPaint); //创建新的图层,进行图像合成 int saveCount = canvas.saveLayer(0, 0, width, height, wavePaint, Canvas.ALL_SAVE_FLAG); setFrontWavePath(levelHeight, specWidth, translateX); setBehindWavePath(levelHeight, specWidth, translateX); wavePaint.setColor(ContextCompat.getColor(context, R.color.behind_color)); canvas.drawPath(wavePathBehind, wavePaint); wavePaint.setColor(ContextCompat.getColor(context, R.color.front_color)); canvas.drawPath(wavePathFront, wavePaint); //设置Paint的Xfermode circlePaint.setXfermode(xfermode); if(circleBitmap == null){ circleBitmap = createCircleBitmap(); } canvas.drawBitmap(circleBitmap,circleX - circleRadius, 0, circlePaint); circlePaint.setXfermode(null); //释放图层 canvas.restoreToCount(saveCount); } //创建圆形Bitmap private Bitmap createCircleBitmap(){ Bitmap bitmap = Bitmap.createBitmap((int)circleDiameter, (int)circleDiameter, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(circleRadius, circleRadius,circleRadius, paint); return bitmap; }
上面onDraw中新增的代码都给出了注释,主要就是画圆,然后进行图像合成,改之后的效果如下:
这下就没有锯齿了,到这就基本实现能量球效果。
- 能量球效果(贝塞尔曲线)
- Android贝塞尔曲线-波纹(波浪)效果
- 贝塞尔曲线与翻页效果
- 实现弹性组件效果(贝塞尔曲线&&阻尼函数)
- 一个查看贝塞尔曲线效果的网站
- iOS 贝塞尔曲线实现圆角效果
- 贝塞尔曲线之购物车动画效果
- 贝塞尔曲线实现球形一变二动画效果
- 贝塞尔曲线之购物车动画效果
- Android贝塞尔曲线实现Loading效果
- android贝塞尔曲线之波浪效果
- 运用贝塞尔曲线描绘android翻页效果
- PathMeasure + 贝塞尔曲线实现过山车效果
- 贝塞尔曲线的艺术---弹性效果实现
- CSS 使用 贝塞尔曲线 碰撞效果实现
- 能量球
- 曲线之美(一)贝塞尔曲线
- 曲线之美(一)贝塞尔曲线
- SQL Server 2000 安装包1/17----分成17个压缩包,这里只纪录1个包的地址
- BPF(Berkeley Packet Filter)内核应用性能调优之 高效的驱动级网络数据包处理
- STK11.2.1 With EOIR 11.2.1已经可以正常使用
- Java日常小结
- $.ajax()方法使用案例
- 能量球效果(贝塞尔曲线)
- 漫谈
- 阿里巴巴代码规约插件使用
- navicat for Mac的备份【windows和Mac】
- 【坐在马桶上看算法】算法2:邻居好说话:冒泡排序
- Illegal or Not?
- JAVA 网络编程简单示例
- android-自定义相机遇小米3生成图片花屏
- linux 并发服务器 demo