大家教师节快乐啊,不知道勤学的Coder们有没有去尝试下绘制上篇文章中最后留下的进阶效果,不管怎样,还是一起动手写一遍吧!看看套路是否一致。
水波纹
首先来看图-水波纹中的效果,其具有以下特点:
从内到外四层,内圆外环;
从内到外四个色值;
最内部圆局于View中心;
圆和环同心;
看出以下几点,我们就可以开始按照套路画图了,老套路走起(在以后自定义View部分新建项目及类相关的描述不再赘述)。
声明画笔和宽高
1.声明画笔及宽高
如上分析,我们需要两个画笔,一个用于绘制内圆,一个用于绘制外环。
/** * 绘制最中心圆的Paint */ private Paint mInnerCirclePaint; /** * 绘制外部圆环的Paint */ private Paint mOutterRingPaint; /** * View宽度 */ private int mWidth; /** * View高度 */ private int mHeight; /** * 外环宽度 */ private int mOuttterRingWidth = 50;2.初始化画笔并在构造函数内调用
由于外部为圆环,所以外部画笔样式设置为空心,内部圆画笔样式设置为实心,同时设置画笔宽度为外部圆环宽度。
public WaveView(Context context) { super(context); init(); } public WaveView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mInnerCirclePaint.setColor(Color.BLUE); /** 内部画笔为实心 **/ mInnerCirclePaint.setStyle(Style.FILL); mOutterRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mOutterRingPaint.setColor(Color.BLUE); /** 外部画笔为空心 **/ mOutterRingPaint.setStyle(Style.STROKE); mOutterRingPaint.setStrokeWidth(mOuttterRingWidth); }3.初始化宽高
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (w > 0 && h > 0){ mWidth = w; mHeight = h; } }计算Points
声明内圆半径,圆环宽度,计算各圆的半径,同心圆及圆环,圆心位于View中心。
如图-水波纹内部距离说明,外环所在圆依次为(radius为外环半径,mInnerRadius为内圆半径,mOutterRingWidth为环宽度):
一环:半径与内圆半径一致,radius = mInnerRadius+(mOutterRingWidth/2)1;
二环:半径等于内圆半径+圆环宽度,radius = mInnerRadius + (mOutterRingWidth/2)3;
…
依次类推,我们可以得到外部圆环半径公式:
radius = mInnerRadius + (mOutterRingWidth/2) * i;(i取1,3,5,7,9…)
如此我们就可以开始撸码了。
/* 声明必要变量 */ /** * 内圆半径 */ private int mInnerRadius = 50; /** * 存储计算所得的外环半径 */ private int[] mRadius = new int[4]; /* 计算外环半径 */ private void calculateRadius() { for (int i = 0; i < 4; i++) { mRadius[i] = mInnerRadius + (i * 2 + 1) * mOuttterRingWidth / 2; } }获取画布绘制圆及圆环
重写onDraw函数获取canvas,并绘制圆环及内圆。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); calculateRadius(); canvas.drawCircle(mWidth / 2, mHeight / 2, mInnerRadius, mInnerCirclePaint); for (int i = 0; i < 4; i++) { /** 改变外环的颜色透明度 **/ mOutterRingPaint.setAlpha(255 - (int) (255 * ((float) (i + 1) / 5))); canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius[i], mOutterRingPaint); } }至于运行效果,大家自己动手试一下喽!
动起来的水波纹
虽然我们画出来了水波纹,但是和蔼的产品还是会批斗你的,他会说,你家水波纹静态的哦?这一秒钟心里是不是有一万只羊驼奔腾?哈哈!奔腾归奔腾,需求我们还是要实现下滴。
那么我们来观察下现实中的水波纹,不难发现与图-水波纹形成 相似的过程。
我们可以看出水波纹动态形成的本质是,外部圆环逐步扩张增加形成的。那么我们只需要动态控制外部圆环的绘制个数,就可以让它动起来了。
属性动画
说到控制外环个数动态增长,做过动画的朋友第一个直觉肯定就是属性动画喽,这样是值变化,所以我们使用ValueAnimator即可(关于属性动画,帧动画,View动画相关的细节,我们在后续文章中单独说明)。
1.声明动画相关的成员
/** * 控制外环个数变化的属性动画对象 */ private ValueAnimator mValueAnimator; /** * 绘制的外环总个数 */ private int mOutterRingCount = 4;2.初始化动画对象并开始
public void startAnimation(){ //创建ValueAnimator对象,按照整型值从0变化到4 mValueAnimator = ValueAnimator.ofInt(0,5); //设置动画重复类型,RESTART--重新开始,REVERSE--值反转 mValueAnimator.setRepeatMode(ValueAnimator.RESTART); //设置动画重复次数,-1--不限制次数 mValueAnimator.setRepeatCount(-1); mValueAnimator.setDuration(2000); mValueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mOutterRingCount = (int) valueAnimator.getAnimatedValue(); postInvalidate(); } }); mValueAnimator.start(); }3.更新onDraw循环参数
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); calculateRadius(); canvas.drawCircle(mWidth / 2, mHeight / 2, mInnerRadius, mInnerCirclePaint); for (int i = 0; i < mOutterRingCount; i++) { mOutterRingPaint.setAlpha(255 - (int) (255 * ((float) (i + 1) / 5))); canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius[i], mOutterRingPaint); } }运行效果见gif,至此我们就完成了水波纹自定义View的开发,怎么样?是不是很有趣啊.