Android中怎么通過自定義View實現(xiàn)打鉤動畫功能,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
公司主營業(yè)務(wù):成都網(wǎng)站制作、網(wǎng)站建設(shè)、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出華坪免費做網(wǎng)站回饋大家。
//計數(shù)器 private int ringCounter = 0; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isChecked) { ... return; } //畫圓弧進度,每次繪制都自加12個單位,也就是圓弧又掃過了12度 //這里的12個單位先寫死,后面我們可以做一個配置來實現(xiàn)自定義 ringCounter += 12; if (ringCounter >= 360) { ringCounter = 360; } canvas.drawArc(mRectF, 90, ringCounter, false, mPaintRing); ... //強制重繪 postInvalidate(); }
這里,我們定義了一個計數(shù)器ringCounter
, 當(dāng)繪制的時候,是根據(jù)12個單位進行自增到達360,從而模擬進度的變化。
仔細(xì)想想
通過改變自增的單位來控制動畫速度的變化,這很難調(diào)整得使自己滿意,此時我們可以想到,使動畫速度執(zhí)行快慢的根本就是控制時間啊,如果可以用時間來控制動畫速度那得方便多了動畫分為4步執(zhí)行,如果每一步動畫都用手寫計數(shù)器來實現(xiàn),那得定義4個成員變量或者更多,太多成員變量只會讓代碼更加混亂如果動畫要加上插值器,那手寫的計數(shù)器根本無法滿足看到上面的分析,我無法接受了
3. 改改改
那么怎么去改善上面所說的問題呢,答案就是用自定義的屬性動畫來解決了,所以這篇文章主要的講的地方就是用屬性動畫來替換手寫的計數(shù)器,盡可能的保證代碼邏輯的清晰,特別是onDraw()
方法中的代碼。
使用屬性動畫的一個好處就是,給定數(shù)值的范圍,它會幫你生成一堆你想要的數(shù)值,配合插值器還要意想不到的效果呢,下一面就一步一步針對動畫執(zhí)行的部分進行重構(gòu)
3.1 繪制圓環(huán)進度條
首先,使用自定義的ObjectAnimator
來模擬進度
//ringProgress是自定義的屬性名稱,生成數(shù)值的范圍是0 - 360,就是一個圓的角度 ObjectAnimator mRingAnimator = ObjectAnimator.ofInt(this, "ringProgress", 0, 360); //定義動畫執(zhí)行的時間,很好的替代之前使用自增的單位來控制動畫執(zhí)行的速度 mRingAnimator.setDuration(mRingAnimatorDuration); //暫時不需要插值器 mRingAnimator.setInterpolator(null);
自定義屬性動畫,還需要配置相應(yīng)的setter
和getter
,因為在動畫執(zhí)行的時候,會找相應(yīng)的setter
去改變相應(yīng)的值。
private int getRingProgress() { return ringProgress; } private void setRingProgress(int ringProgress) { //動畫執(zhí)行的時候,會調(diào)用setter //這里我們可以將動畫生成的數(shù)值記錄下來,用變量存起來,在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); //當(dāng)進度圓環(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); //最后的放大再回彈的動畫,改變畫筆的寬度來實現(xiàn) //而畫筆的寬度,則是的變化范圍是 //首先從初始化寬度開始,再到初始化寬度的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) { //設(shè)置透明度,可以不用變量來保存了 //直接將透明度的值設(shè)置到畫筆里面即可 mPaintTick.setAlpha(tickAlpha); postInvalidate(); } private float getRingStrokeWidth() { return mPaintRing.getStrokeWidth(); } private void setRingStrokeWidth(float strokeWidth) { //設(shè)置畫筆寬度,可以不用變量來保存了 //直接將畫筆寬度設(shè)置到畫筆里面即可 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í)行動畫
//這里定義了一個標(biāo)識符,用于告訴程序,動畫每次只能執(zhí)行一次 if (!isAnimationRunning) { isAnimationRunning = true; //執(zhí)行動畫 mFinalAnimatorSet.start(); }
3.5 每個方法最好能有單一的職責(zé)
如果將定義屬性動畫的方法放在onDraw()
中,我個人感覺很亂,并且再仔細(xì)看看,這幾個屬性動畫是不需要動態(tài)變化的,為什么不抽出來在一開始的時候就初始化呢?
so,我們將定義屬性動畫的代碼抽出來,并且放到構(gòu)造函數(shù)中初始化
public TickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); ... initAnimatorCounter(); }
/** * 用ObjectAnimator初始化一些計數(shù)器 */ 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); ... //最后的放大再回彈的動畫,改變畫筆的寬度來實現(xiàn) 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()
方法中,只負(fù)責(zé)簡單的繪制,什么都不管
@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動畫替換計數(shù)器 if (!isAnimationRunning) { isAnimationRunning = true; mFinalAnimatorSet.start(); } }
看完上述內(nèi)容,你們掌握Android中怎么通過自定義View實現(xiàn)打鉤動畫功能的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
分享文章:Android中怎么通過自定義View實現(xiàn)打鉤動畫功能
標(biāo)題路徑:http://www.chinadenli.net/article48/pidsep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、虛擬主機、網(wǎng)站內(nèi)鏈、網(wǎng)站排名、品牌網(wǎng)站設(shè)計、網(wǎng)站收錄
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)