前言:公司在做的一个项目,要求在地图上以水波气泡的形式来显示站点,并且气泡要有水波的动态效果。好吧!既然有这样的需求,那就手撸一款水波气泡吧!
效果图预览
最后完成的效果图如下
不想看文章的话,可以点击这里,直接获取源码。
实现方式
步骤拆解
在需要自定义view的时候,我首先要做的就是将最后要实现的效果来进行拆分,拆分成许多小的步骤,然后一步步的来实现,最终达到想要的效果。
可以将文章开始的时候的效果图拆分成以下几部分:
- 画出气泡后面的白色背景。
- 画内部的紫色气泡。
- 用贝塞尔曲线让内部的紫色气泡动起来。
拆解之后,就可以按照拆解的步骤来一步步实现了。
画白色背景
这里画白色背景有以下两种方式:
- 用
path
直接描述一个白色背景的形状。 - 用
path
描述一个三角形,然后在画出一个圆形,即成最终的白色背景了。
第一种方式如下图的左图,用path
直接描述出了白色背景,这种方式可以用path.addArc()
来画上部弧形,然后用path.moveTo()
和path.lineTo()
方法描述出下部分的尖角。
第二种实现的方式如下图的右图,直接画出一个圆,再用path.moveTo()
和path.lineTo()
方法来描述出下部分的尖角。
本文采用的是第二种方式来实现的,具体代码如下
//此处代码是下部尖角的path mBackgroundPath.moveTo(mResultWidth / 2 - mOutRadius / 2, mResultWidth / 2 + mOutRadius / 2); mBackgroundPath.lineTo(mResultWidth / 2, mResultWidth / 2 + mOutRadius + mOutRadius / 4); mBackgroundPath.lineTo(mResultWidth / 2 + mOutRadius / 2, mResultWidth / 2 + mOutRadius / 2); //画外部背景 canvas.drawPath(mBackgroundPath, mBackgroundPaint); canvas.drawCircle(mResultWidth / 2, mResultWidth / 2, mOutRadius, mBackgroundPaint);
画内部的气泡
内部的气泡的形状其实就是缩小的外部背景,具体的代码如下
//内部气泡的尖角 mBubblesPath.moveTo(mResultWidth / 2 - mOutRadius / 2, mResultWidth / 2 + mOutRadius / 2 - dp2px(getContext(), 5)); mBubblesPath.lineTo(mResultWidth / 2, mResultWidth / 2 + mOutRadius + mOutRadius / 4 - dp2px(getContext(), 5)); mBubblesPath.lineTo(mResultWidth / 2 + mOutRadius / 2, mResultWidth / 2 + mOutRadius / 2 - dp2px(getContext(), 5)); //画圆 mBubblesPath.addCircle(mResultWidth / 2, mResultWidth / 2, mInnerRadius, Path.Direction.CCW);
到这里已经将气泡的基本形状画出来了,见下图
我们会发现气泡内部的颜色是渐变色,那渐变色是怎么设置的呢?其实自定义view就是将想要的效果通过画笔画在画布上,实现颜色的渐变肯定就是通过设置画笔的属性来实现的了,设置渐变色的代码如下
//设置渐变色 Shader shader = new LinearGradient(mResultWidth / 2, mResultWidth / 2 - mInnerRadius, mResultWidth / 2, mResultWidth / 2 + mInnerRadius, Color.parseColor("#9592FB"), Color.parseColor("#3831D4"), Shader.TileMode.CLAMP); mBubblesPaint.setShader(shader);
LinearGradient(float x0, float y0, float x1, float y1, @ColorInt int color0, @ColorInt int color1, @NonNull TileMode tile)
x0
y0
x1
y1
:渐变的两个端点的位置color0
color1
是端点的颜色tile
:端点范围之外的着色规则,类型是TileMode
。TileMode
一共有 3 个值可选:CLAMP
,MIRROR
和REPEAT
。一般用CLAMP
就可以了。