);
}
public Wave(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public Wave(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化参数
init(context,attrs);
}
}
接下来是初始化函数,在此处我们获取到自定义的颜色及文字参数,并初始化各种画笔,代码比较简单,看注释内容即可
- private void init(Context context, AttributeSet attrs) {
- //获取自定义参数值
- TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Wave);
- //自定义颜色和文字
- color = array.getColor(R.styleable.Wave_color, Color.rgb(41, 163, 254));
- text = array.getString(R.styleable.Wave_text);
- array.recycle();
- //图形及路径填充画笔(抗锯齿、填充、防抖动)
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setColor(color);
- mPaint.setDither(true);
- //文字画笔(抗锯齿、白色、粗体)
- textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- textPaint.setColor(Color.WHITE);
- textPaint.setTypeface(Typeface.DEFAULT_BOLD);
- //闭合波浪路径
- path = new Path();
- }
接下来是生成波浪线的方法,示意图如下:
波浪生成原理
将Path起点移动到最左边粉色点处,然后绘制两个周期的长度的波形(一上一下是一个周期),每个周期在x轴的跨度为此控件的宽度控制点距波形的轴线的绝对高度是整个控件的3/20,当然想让波形波动幅度大的话这个比例可以随意调整,接下来就用前边讲到的rQuadTo( )来生成闭合的波浪图形,其中mWidth为控件的宽度,mHeight为控件的高度
- private Path getActionPath(float percent) {
- Path path = new Path();
- int x = -mWidth;
- //当前x点坐标(根据动画进度水平推移,一个动画周期推移的距离为一个周期的波长)
- x += percent * mWidth;
- //波形的起点
- path.moveTo(x, mHeight / 2);
- //控制点的相对宽度
- int quadWidth = mWidth / 4;
- //控制点的相对高度
- int quadHeight = mHeight / 20 * 3;
- //第一个周期波形
- path.rQuadTo(quadWidth, quadHeight, quadWidth * 2, 0);
- path.rQuadTo(quadWidth, -quadHeight, quadWidth * 2, 0);
- //第二个周期波形
- path.rQuadTo(quadWidth, quadHeight, quadWidth * 2, 0);
- path.rQuadTo(quadWidth, -quadHeight, quadWidth * 2, 0);
- //右侧的直线
- path.lineTo(x + mWidth * 2, mHeight);
- //下边的直线
- path.lineTo(x, mHeight);
- //自动闭合补出左边的直线
- path.close();
- return path;
- }
上边代码所表示的闭合路径如下图
闭合的波浪图形
接下来就是重头戏onDraw了
- @Override
- protected void onDraw(Canvas canvas) {
- //底部的字
- textPaint.setColor(color);
- drawCenterText(canvas, textPaint, text);
- //上层的字
- textPaint.setColor(Color.WHITE);
- //生成闭合波浪路径
- path = getActionPath(currentPercent);
- canvas.clipPath(path);
- //裁剪成圆形
- canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mPaint);
- drawCenterText(canvas, textPaint, text);
- }
这里绘制思路是:在canvas上绘制蓝色的文字 ——>将画布裁剪成波浪形 ——>在波浪形画布上绘制圆 ——>在波浪形画布上绘制文字,这里一定要注意绘制顺序,先绘制的在下部,后绘制的在上部。
细心的朋友一定看到了一个函数drawCenterText(canvas, textPaint, text)没错,这个函数就是讲文字绘于控件正中心的方法。有的读者可能一直在使用Canvas.drawText( String text, float x, float y, Paint paint) 这个方法,但是参数中的(x,y)到底是哪个坐标呢,是文字左上角的点的坐标吗?不是的,接下来我们用代码验证一下这个(x,y)到底在文字的哪个部位
- canvas.drawText(text,600,200,textPaint);
- canvas.drawCircle(600,200,3,paint);
- canvas.translate(600, 200);
- Rect bgRect=new Rect(0,0,1000,400);
- canvas.drawRect(bgRect,bgPaint);
-
- Rect textBound=new Rect();
- textPaint.getTextBounds(text,0,text.length(),textBound);
- paint.setColor(Color.RED);
- canvas.drawRect(textBound,paint);
-
- Paint.FontMetrics metrics=textPaint.getFontMetrics();
- paint.setColor(Color.RED);
- // ascent 橙色
- paint.setColor(Color.rgb(255,126,0));
- canvas.drawLine(0, metrics.ascent, 500,metrics.ascent, paint);
- // descent
- paint.setColor(Color.rgb(255,0,234));
- canvas.drawLine(0, metrics.descent, 500, metrics.descent, paint);
- // top
- paint.setColor(Color.DKGRAY);
- canvas.drawLine(0,
|