Android自定义View:关于打钩小动画的思考重构,android开发入门与实战作者

本文介绍了如何在Android中创建一个自定义View,展示了一个精致的打钩小动画的实现过程,包括圆环收缩、钩形动画及放大回弹效果。通过代码重构,使每个方法具有单一职责,提高代码可读性和维护性。文章还提供了项目的GitHub链接,供读者参考学习。
摘要由CSDN通过智能技术生成

自定义属性动画,还需要配置相应的settergetter,因为在动画执行的时候,会找相应的setter去改变相应的值。

private int getRingProgress() {
return ringProgress;
}

private void setRingProgress(int ringProgress) {
//动画执行的时候,会调用setter
//这里我们可以将动画生成的数值记录下来,用变量存起来,在ondraw的时候用
this.ringProgress = ringProgress;
//记得重绘
postInvalidate();
}

最后,在onDraw()中画图

//画圆弧进度
canvas.drawArc(mRectF, 90, ringProgress, false, mPaintRing);

3.2 绘制向圆心收缩的动画

同理,也是造一个属性动画

//这里自定义的属性是圆收缩的半径
ObjectAnimator mCircleAnimator = ObjectAnimator.ofInt(this, “circleRadius”, radius - 5, 0);
//加一个减速的插值器
mCircleAnimator.setInterpolator(new DecelerateInterpolator());
mCircleAnimator.setDuration(mCircleAnimatorDuration);

setter/getter也是类似就不说了

最后onDraw()中绘制

//画背景
mPaintCircle.setColor(checkBaseColor);
canvas.drawCircle(centerX, centerY, ringProgress == 360 ? radius : 0, mPaintCircle);
//当进度圆环绘制好了,就画收缩的圆
if (ringProgress == 360) {
mPaintCircle.setColor(checkTickColor);
canvas.drawCircle(centerX, centerY, circleRadius, mPaintCircle);
}

3.3 绘制钩和放大再回弹的效果

这是两个独立的效果,这里同时执行,我就合在一起说了

首先也是定义属性动画

//勾出来的透明渐变
ObjectAnimator mAlphaAnimator = ObjectAnimator.ofInt(this, “tickAlpha”, 0, 255);
mAlphaAnimator.setDuration(200);
//最后的放大再回弹的动画,改变画笔的宽度来实现
//而画笔的宽度,则是的变化范围是
//首先从初始化宽度开始,再到初始化宽度的n倍,最后又回到初始化的宽度
ObjectAnimator mScaleAnimator = ObjectAnimator.ofFloat(this, “ringStrokeWidth”, mPaintRing.getStrokeWidth(), mPaintRing.getStrokeWidth() * SCALE_TIMES, mPaintRing.getStrokeWidth() / SCALE_TIMES);
mScaleAnimator.setInterpolator(null);
mScaleAnimator.setDuration(mScaleAnimatorDuration);

//打钩和放大回弹的动画一起执行
AnimatorSet mAlphaScaleAnimatorSet = new AnimatorSet();
mAlphaScaleAnimatorSet.playTogether(mAlphaAnimator, mScaleAnimator);

getter/setter

private int getTickAlpha() {
return 0;
}

private void setTickAlpha(int tickAlpha) {
//设置透明度,可以不用变量来保存了
//直接将透明度的值设置到画笔里面即可
mPaintTick.setAlpha(tickAlpha);
postInvalidate();
}

private float getRingStrokeWidth() {
return mPaintRing.getStrokeWidth();
}

private void setRingStrokeWidth(float strokeWidth) {
//设置画笔宽度,可以不用变量来保存了
//直接将画笔宽度设置到画笔里面即可
mPaintRing.setStrokeWidth(strokeWidth);
postInvalidate();
}

最后,同理在onDraw()中绘制即可

if (circleRadius == 0) {
canvas.drawLines(mPoints, mPaintTick);
canvas.drawArc(mRectF, 0, 360, false, mPaintRing);
}

3.4 依次执行动画

执行多个动画,可以用到AnimatorSet,其中playTogether()是一起执行,playSequentially()是一个挨着一个,step by step执行。

mFinalAnimatorSet = new AnimatorSet();
mFinalAnimatorSet.playSequentially(mRingAnimator, mCircleAnimator, mAlphaScaleAnimatorSet);

最后在onDraw()中执行动画

//这里定义了一个标识符,用于告诉程序,动画每次只能执行一次
if (!isAnimationRunning) {
isAnimationRunning = true;
//执行动画
mFinalAnimatorSet.start();
}

3.5 每个方法最好能有单一的职责

如果将定义属性动画的方法放在onDraw()中,我个人感觉很乱,并且再仔细看看,这几个属性动画是不需要动态变化的,为什么不抽出来在一开始的时候就初始化呢?

so,我们将定义属性动画的代码抽出来,并且放到构造函数中初始化

public TickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

initAnimatorCounter();
}

/**

  • 用ObjectAnimator初始化一些计数器
    */
    private void initAnimatorCounter() {
    /

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

/圆环进度
ObjectAnimator mRingAnimator = ObjectAnimator.ofInt(this, “ringProgress”, 0, 360);

//收缩动画
ObjectAnimator mCircleAnimator = ObjectAnimator.ofInt(this, “circleRadius”, radius - 5, 0);

//勾出来的透明渐变
ObjectAnimator mAlphaAnimator = ObjectAnimator.ofInt(this, “tickAlpha”, 0, 255);

//最后的放大再回弹的动画,改变画笔的宽度来实现
ObjectAnimator mScaleAnimator = ObjectAnimator.ofFloat(this, “ringStrokeWidth”, mPaintRing.getStrokeWidth(), mPaintRing.getStrokeWidth() * SCALE_TIMES, mPaintRing.getStrokeWidth() / SCALE_TIMES);

//打钩和放大回弹的动画一起执行
AnimatorSet mAlphaScaleAnimatorSet = new AnimatorSet();
mAlphaScaleAnimatorSet.playTogether(mAlphaAnimator, mScaleAnimator);

mFinalAnimatorSet = new AnimatorSet();
mFinalAnimatorSet.playSequentially(mRingAnimator, mCircleAnimator, mAlphaScaleAnimatorSet);
}

最后,onDraw()方法中,只负责简单的绘制,什么都不管

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isChecked) {
canvas.drawArc(mRectF, 90, 360, false, mPaintRing);
canvas.drawLines(mPoints, mPaintTick);
return;
}
//画圆弧进度
canvas.drawArc(mRectF, 90, ringProgress, false, mPaintRing);
//画黄色的背景
mPaintCircle.setColor(checkBaseColor);
canvas.drawCircle(centerX, centerY, ringProgress == 360 ? radius : 0, mPaintCircle);
//画收缩的白色圆
if (ringProgress == 360) {
mPaintCircle.setColor(checkTickColor);
canvas.drawCircle(centerX, centerY, circleRadius, mPaintCircle);
}
//画勾,以及放大收缩的动画
if (circleRadius == 0) {
canvas.drawLines(mPoints, mPaintTick);
canvas.drawArc(mRectF, 0, 360, false, mPaintRing);
}
//ObjectAnimator动画替换计数器
if (!isAnimationRunning) {
isAnimationRunning = true;
mFinalAnimatorSet.start();
}
}
最终效果是一样的,代码逻辑一目了然
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MfoxJ2dG-1637900864961)(https://user-gold-cdn.xitu.io/2017/10/29/6d003f6e9194e5d786e4b477c9bc43ef?imageView2/0/w/1280/h/960/ignore-error/1)]
最终效果.gif
所以,个人觉得,在开发中,定时review一下自己的代码,无论对自己,还是对以后维护,是很有帮助的。
That ’ s all~
感谢大家阅读,最后再放一下项目的github地址

Github地址:TickView,一个精致的打钩小动画
github.com/ChengangFen…

图片转存中…(img-MfoxJ2dG-1637900864961)]
最终效果.gif
所以,个人觉得,在开发中,定时review一下自己的代码,无论对自己,还是对以后维护,是很有帮助的。
That ’ s all~
感谢大家阅读,最后再放一下项目的github地址

Github地址:TickView,一个精致的打钩小动画
github.com/ChengangFen…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值