国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android自定義View實現打鉤動畫功能

2019-10-22 18:19:04
字體:
來源:轉載
供稿:網友

先上效果圖

動圖

Android,打鉤動畫,自定義View

靜態(tài)圖

Android,打鉤動畫,自定義View

1. 回顧

【Android自定義View:一個精致的打鉤小動畫】上一篇文章,我們已經實現了基本上實現了控件的效果了,但是...但是...過了三四天后,仔細看回自己寫的代碼,雖然思路還在,但是部分代碼還是不能一下子的看得明白...

我的天,這得立馬重構啊~ 恰好,有個簡友 ChangQin 模仿寫了一下這個控件,我看了后覺得我也可以這樣實現一下。

2. 深思

關于控件繪制的思路,可以去看看 上一篇文章,這里就不再分析了。這里先來分析一下上一篇文章里面,控件里面的一些頑處,哪些地方需要改進。

就拿 繪制圓環(huán)進度 這一步來看

//計數器private int ringCounter = 0;@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isChecked) {  ...  return; } //畫圓弧進度,每次繪制都自加12個單位,也就是圓弧又掃過了12度 //這里的12個單位先寫死,后面我們可以做一個配置來實現自定義 ringCounter += 12; if (ringCounter >= 360) {  ringCounter = 360; } canvas.drawArc(mRectF, 90, ringCounter, false, mPaintRing); ... //強制重繪 postInvalidate();}

這里,我們定義了一個計數器ringCounter, 當繪制的時候,是根據12個單位進行自增到達360,從而模擬進度的變化。

仔細想想

通過改變自增的單位來控制動畫速度的變化,這很難調整得使自己滿意,此時我們可以想到,使動畫速度執(zhí)行快慢的根本就是控制時間啊,如果可以用時間來控制動畫速度那得方便多了動畫分為4步執(zhí)行,如果每一步動畫都用手寫計數器來實現,那得定義4個成員變量或者更多,太多成員變量只會讓代碼更加混亂如果動畫要加上插值器,那手寫的計數器根本無法滿足看到上面的分析,我無法接受了

3. 改改改

那么怎么去改善上面所說的問題呢,答案就是用自定義的屬性動畫來解決了,所以這篇文章主要的講的地方就是用屬性動畫來替換手寫的計數器,盡可能的保證代碼邏輯的清晰,特別是onDraw()方法中的代碼。

使用屬性動畫的一個好處就是,給定數值的范圍,它會幫你生成一堆你想要的數值,配合插值器還要意想不到的效果呢,下一面就一步一步針對動畫執(zhí)行的部分進行重構

3.1 繪制圓環(huán)進度條

首先,使用自定義的ObjectAnimator來模擬進度

//ringProgress是自定義的屬性名稱,生成數值的范圍是0 - 360,就是一個圓的角度ObjectAnimator mRingAnimator = ObjectAnimator.ofInt(this, "ringProgress", 0, 360);//定義動畫執(zhí)行的時間,很好的替代之前使用自增的單位來控制動畫執(zhí)行的速度mRingAnimator.setDuration(mRingAnimatorDuration);//暫時不需要插值器mRingAnimator.setInterpolator(null);

自定義屬性動畫,還需要配置相應的settergetter,因為在動畫執(zhí)行的時候,會找相應的setter去改變相應的值。

private int getRingProgress() { return ringProgress;}private void setRingProgress(int ringProgress) { //動畫執(zhí)行的時候,會調用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);//當進度圓環(huán)繪制好了,就畫收縮的圓if (ringProgress == 360) { mPaintCircle.setColor(checkTickColor); canvas.drawCircle(centerX, centerY, circleRadius, mPaintCircle);}

3.3 繪制鉤和放大再回彈的效果

這是兩個獨立的效果,這里同時執(zhí)行,我就合在一起說了

首先也是定義屬性動畫

//勾出來的透明漸變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);//打鉤和放大回彈的動畫一起執(zhí)行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 依次執(zhí)行動畫

執(zhí)行多個動畫,可以用到AnimatorSet,其中playTogether()是一起執(zhí)行,playSequentially()是一個挨著一個,step by step執(zhí)行。

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

最后在onDraw()中執(zhí)行動畫

//這里定義了一個標識符,用于告訴程序,動畫每次只能執(zhí)行一次if (!isAnimationRunning) { isAnimationRunning = true; //執(zhí)行動畫 mFinalAnimatorSet.start();}

3.5 每個方法最好能有單一的職責

如果將定義屬性動畫的方法放在onDraw()中,我個人感覺很亂,并且再仔細看看,這幾個屬性動畫是不需要動態(tài)變化的,為什么不抽出來在一開始的時候就初始化呢?

so,我們將定義屬性動畫的代碼抽出來,并且放到構造函數中初始化

public TickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); ... initAnimatorCounter();}
/** * 用ObjectAnimator初始化一些計數器 */private void initAnimatorCounter() { //圓環(huán)進度 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); ... //打鉤和放大回彈的動畫一起執(zhí)行 AnimatorSet mAlphaScaleAnimatorSet = new AnimatorSet(); mAlphaScaleAnimatorSet.playTogether(mAlphaAnimator, mScaleAnimator); mFinalAnimatorSet = new AnimatorSet(); mFinalAnimatorSet.playSequentially(mRingAnimator, mCircleAnimator, mAlphaScaleAnimatorSet);}

最后,onDraw()方法中,只負責簡單的繪制,什么都不管

@Overrideprotected 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(); }}

最終效果是一樣的,代碼邏輯一目了然

Android,打鉤動畫,自定義View

所以,個人覺得,在開發(fā)中,定時review一下自己的代碼,無論對自己,還是對以后維護,是很有幫助的。

That ' s all~感謝大家閱讀,最后再放一下項目的github地址

> Github地址:TickView,一個精致的打鉤小動畫https://github.com/ChengangFeng/TickView

以上就是小編給大家整理的關于自定義View實現打鉤動畫功能的全部內容,大家可以測試下,如果還有任何問題可以在下方的留言區(qū)討論,感謝對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 托克托县| 黑河市| 巫溪县| 永春县| 东乌珠穆沁旗| 岐山县| 德钦县| 玉林市| 苏尼特左旗| 砀山县| 会理县| 宁夏| 正镶白旗| 大关县| 含山县| 宁强县| 祁东县| 沁水县| 炎陵县| 阳西县| 藁城市| 肥城市| 龙门县| 广西| 朝阳市| 曲水县| 漳平市| 呈贡县| 徐闻县| 新乡县| 长葛市| 毕节市| 铁力市| 静海县| 博白县| 越西县| 囊谦县| 德钦县| 额尔古纳市| 大埔县| 阳西县|