本篇內(nèi)容介紹了“如何實現(xiàn)與優(yōu)化搶購倒計時自定義控件”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)自2013年起,先為莊浪等服務(wù)建站,莊浪等地企業(yè),進行企業(yè)商務(wù)咨詢服務(wù)。為莊浪企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
隨著網(wǎng)購的持續(xù)發(fā)展,搶購類倒計時在各類電商應(yīng)用中已十分常見,這種設(shè)計可以提高用戶的點擊率和下單率等。
但是國內(nèi)的電商應(yīng)用大部分都僅支持中文,不適配其他的語言,因此當?shù)褂嫊r與其他文案處于同一行展示時,無需考慮倒計時的展示方式。在海外應(yīng)用中,由于需要適配各種語言,有些小語種的文案較長,因此當?shù)褂嫊r和其他文案處于同一行展示時,需要充分考慮多語言的適配,如何優(yōu)雅地完成倒計時自適應(yīng)顯示是一個值得深思的問題。
為進一步優(yōu)化倒計時效果,我們?yōu)榈褂嫊r增加了數(shù)字滾動動畫,如下圖所示。
該控件預期展現(xiàn)兩種狀態(tài),距離活動開始還有X天XX:XX:XX 和距離活動結(jié)束還有X天XX:XX:XX,因此需要一個活動狀態(tài)屬性,并通過這個活動開始與否的屬性設(shè)置時間前的文案。具體時間時分秒之間相互獨立,因此將它們拆分成獨立的textview進行處理。
倒計時控件的核心是計時器,安卓中已經(jīng)有現(xiàn)成的CountDownTimer類可供使用以實現(xiàn)倒計時功能。此外,還需要實現(xiàn)一些監(jiān)聽的接口。
首先,定義回調(diào)接口
public interface OnCountDownTimerListener { /** * 倒計時正在進行時調(diào)用的方法 * * @param millisUntilFinished 剩余的時間(毫秒) */ void onRemain(long millisUntilFinished); /** * 倒計時結(jié)束 */ void onFinish(); /** * 每過一分鐘調(diào)用的方法 */ void onArrivalOneMinute(); }
在該接口中定義三個方法:
onRemain(long millisUntilFinished):倒計時進行中回調(diào)的方法,用于后續(xù)功能的拓展
onFinish():倒計時結(jié)束回調(diào),用于活動狀態(tài)的切換和計時的暫停等
onArrivalOneMinute():每過一分鐘回調(diào),用于定時上報的埋點
其次,初始化自定義view,基于實際開發(fā)需求,將整個控件細分為修飾文案、天數(shù)、時、分、秒等幾個獨立的textview,并在自定義BaseCountDownTimerView中初始化:
private void init() { mDayTextView = findViewById(R.id.days_tv); mHourTextView = findViewById(R.id.hours_tv); mMinTextView = findViewById(R.id.min_tv); mSecondTextView = findViewById(R.id.sec_tv); mHeaderText = findViewById(R.id.header_tv); mDayText = findViewById(R.id.new_arrival_day); }
首先構(gòu)造設(shè)置剩余時間的方法,入?yún)⑹鞘S嗟暮撩霐?shù),在方法內(nèi)部將時間轉(zhuǎn)化為具體的天時分秒,并將結(jié)果賦予給textview
private void setSecond(long millis) { long day = millis / ONE_DAY; long hour = millis / ONE_HOUR - day * 24; long min = millis / ONE_MIN - day * 24 * 60 - hour * 60; long sec = millis / ONE_SEC - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60; String second = (int) sec + ""; // 秒 String minute = (int) min + ""; // 分 String hours = (int) hour + ""; // 時 String days = (int) day + ""; //天 if (hours.length() == 1) { hours = "0" + hours; } if (minute.length() == 1) { minute = "0" + minute; } if (second.length() == 1) { second = "0" + second; } if (day == 0) { mDayTextView.setVisibility(GONE); mDayText.setVisibility(GONE); } else { setDayText(day); mDayTextView.setVisibility(VISIBLE); mDayText.setVisibility(VISIBLE); } mDayTextView.setText(days); if (mFirstSetTimer) { mHourTextView.setInitialNumber(hours); mMinTextView.setInitialNumber(minute); mSecondTextView.setInitialNumber(second); mFirstSetTimer = false; } else { mHourTextView.flipNumber(hours); mMinTextView.flipNumber(minute); mSecondTextView.flipNumber(second); } }
需要注意的是,當單位時間為個位數(shù)時,為了視覺效果的統(tǒng)一,要在數(shù)字前加“0”進行補位。
其次,構(gòu)建一個創(chuàng)建倒計時的方法,其代碼如下:
private void createCountDownTimer(final int eventStatus) { if (mCountDownTimer != null) { mCountDownTimer.cancel(); } mCountDownTimer = new CountDownTimer(mMillis, 1000) { @Override public void onTick(long millisUntilFinished) { //策劃要求:倒計時為00:00:01時,活動狀態(tài)刷新,倒計時不展示00:00:00這個狀態(tài) if (millisUntilFinished >= ONE_SEC) { setSecond(millisUntilFinished); //當活動狀態(tài)為進行中時,每隔一分鐘調(diào)用一次回調(diào) if (eventStatus == HomeItemViewNewArrival.EVENT_START) { mArrivalOneMinuteFlag--; if (mArrivalOneMinuteFlag == Constant.ZERO) { mArrivalOneMinuteFlag = Constant.SIXTY; mOnCountDownTimerListener.onArrivalOneMinute(); } } } } @Override public void onFinish() { mOnCountDownTimerListener.onFinish(); } }; }
在該方法中,創(chuàng)建一個倒計時實例CountDownTimer,CountDownTimer() 有兩個參數(shù),分別是剩余的總時間和刷新間隔。
在實例的onTick()方法中,調(diào)用setSecond()方法在每次間隔時間(也就是1s)后定期刷新view,完成倒計時控件的更新。此外,產(chǎn)品中還有一個一分鐘定期上報埋點的需求,也可以在onTick()方法中完成。在實際項目事件中,若有定時的任務(wù)需求,也可在該方法中自由設(shè)置。最后,還需重寫該CountDownTimer的onFinish()方法,觸發(fā)listener接口里的onFinish()
首先是設(shè)置倒計時的監(jiān)聽事件:
public void setDownTimerListener(OnCountDownTimerListener listener) { this.mOnCountDownTimerListener = listener; }
其次是外露一個設(shè)置初始時間和活動開始或結(jié)束文案的方法:
public void setDownTime(long millis) { this.mMillis = millis; } public void setHeaderText(int eventStatus) { if (eventStatus == HomeItemViewNewArrival.EVENT_NOT_START) { mHeaderText.setText("Start in"); } else { mHeaderText.setText("Ends in"); } }
最后,也是最重要的,需要給倒計時類設(shè)計開始與取消倒計時的方法:
public void startDownTimer(int eventStatus) { mArrivalOneMinuteFlag = Constant.SIXTY; mFirstSetTimer = true; //設(shè)置需要倒計時的初始值 setSecond(mMillis); createCountDownTimer(eventStatus);// 創(chuàng)建倒計時 mCountDownTimer.start(); } public void cancelDownTimer() { mCountDownTimer.cancel(); }
在開始倒計時的方法中,初始化倒計時的初始值并創(chuàng)建倒計時,最后調(diào)用CountDownTimer實例的start()方法開始倒計時。在取消的方法中,直接調(diào)用CountDownTimer實例的cancel()方法取消倒計時。
實際調(diào)用倒計時控件時,只需在具體布局中添加該倒計時類布局,在調(diào)用的類中實例化BaseCountDownTimerView。接著,使用實例的setDownTime()、setHeaderText()初始化數(shù)據(jù),使用setDownTimerListener()給view實例設(shè)置監(jiān)聽。
最后調(diào)用startDownTimer()開啟倒計時。
if (view != null) { view.setDownTime(mDuration); view.setHeaderText(mEventStatus); view.startDownTimer(mEventStatus); view.setDownTimerListener(new BaseCountDownTimerView.OnCountDownTimerListener() { @Override public void onRemain(long millisUntilFinished) { } @Override public void onFinish() { view.cancelDownTimer(); if (bean.mNewArrivalType == TYPE_EVENT && mEventStatus == EVENT_START) { mEventStatus = EVENT_END; //活動狀態(tài)之前為進行中,倒計時變?yōu)?,如果還有下一個活動/新品,則刷新為下一個活動/新品的數(shù)據(jù) refreshNewArrivalBeanDate(bean); onBindView(bean, 1, true, null); } else { setEventStatus(bean); } } @Override public void onArrivalOneMinute() { } });
在多語言環(huán)境或者不同屏幕條件下,某些語種的控件長度過長,需要自適應(yīng)控件進行折行顯示以適應(yīng)UI規(guī)范
原本考慮只實例化一個自定義倒計時控件的對象,但是在設(shè)計對象布局的過程中發(fā)現(xiàn),一個對象不方便同時實現(xiàn)在行尾展示或折行后在第二行行首顯示。因此,本文采用了在布局的時候同時預置兩個倒計時對象的方法,一個對象位于行尾,另一個位于第二行的行首。
在measure過程中,如果測量得到控件的寬度大于某一個寬度閾值,則初始化次行行首的view,并將行尾的view可見狀態(tài)置為Gone,若小于某一個寬度閾值,則初始化行尾的view,并將次行行首的view可見狀態(tài)置為Gone
首先來看一看xml布局文件,以下是標題加倒計時位于行尾的一個整體布局文件main_view_header_new_arrival
它的實際展示效果如下圖所示
但是此布局只能展示單行能展示所有內(nèi)容的情況,因此還需要在此布局上拓展雙行展示的情況,再看一看main_list_item_home_new_arrival的布局
它的實際展示效果如下圖所示
在類中將以上兩個view分別進行實例關(guān)聯(lián)。
View.inflate(getContext(), R.layout.main_list_item_home_new_arrival, this); mBaseCountDownTimerViewShort = findViewById(R.id.count_down_timer_short); //行尾倒計時view mBaseCountDownTimerViewLong = findViewById(R.id.count_down_timer_long); //次行行首倒計時view
通過以上的步驟搞定了兩種情況下倒計時控件的布局,接下來就該考慮折行展示的判斷條件了。
在多語言環(huán)境中,標題textview與倒計時view的寬度都是不確定的,因此需要綜合考慮兩個控件的寬度。同時,因為策劃要求,還需考慮某些語種特殊情況的展示要求。判斷代碼如下所示:
private boolean isShortCountDownTimerViewShow() { String languageCode = LocaleManager.getInstance().getCurrentLanguage(); if (Constant.EN_US.equals(languageCode) || Constant.EN_GB.equals(languageCode) || Constant.EN_AU.equals(languageCode)) { //因策劃要求,美式英語、英國英語、澳大利亞英語,強制在New Arrivals標題欄右側(cè)展示 return true; } else { View newArrivalHeader = inflate(mContext, R.layout.main_view_header_new_arrival, null); TextView newArrivalTextView = newArrivalHeader.findViewById(R.id.new_arrival_txt); LinearLayout countDownTimer = newArrivalHeader.findViewById(R.id.count_down_timer_short); int measureSpecW = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); int measureSpecH = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); newArrivalTextView.measure(measureSpecW, measureSpecH); countDownTimer.measure(measureSpecW, measureSpecH); VLog.i(TAG, countDownTimer.getMeasuredWidth() + "--">
在代碼中,可以根據(jù)實際需要定制具體某幾款語言是否換行顯示。
而對于剩下的大多數(shù)語言,可以使用MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)獲取measureSpecW 和 measureSpecH ,第一個參數(shù)是系統(tǒng)測量該View后得到的規(guī)格值,這里使用0代表省略(在系統(tǒng)對該View繪制之前就直接調(diào)用了measure方法,所以寬高為0,該值與最終獲取的寬高無關(guān)),第二個參數(shù)MeasureSpec.UNSPECIFIED代表父容器不對View有任何限制。獲取完成后也就順利完成具體view寬度的測量。
通過該方法的返回值,我們就可以控制兩個倒計時view的展示與隱藏,從而達到自適應(yīng)折行展示的效果。
if (isShortCountDownTimerViewShow()) { initCountDownTimerView(mBaseCountDownTimerViewShort, bean); mBaseCountDownTimerViewShort.setVisibility(VISIBLE); mBaseCountDownTimerViewLong.setVisibility(GONE); } else { initCountDownTimerView(mBaseCountDownTimerViewLong, bean); mBaseCountDownTimerViewShort.setVisibility(GONE); mBaseCountDownTimerViewLong.setVisibility(VISIBLE); }
此外,該方法也不局限于倒計時控件view,針對多語言中各種各樣的自定義view,依然可以使用這種測量方法實現(xiàn)自適應(yīng)換行的美觀展示。
從效果圖上可以看到,時、分、秒都是兩位數(shù),且數(shù)字的變化規(guī)律都相同:首先是從個位數(shù)開始變化,舊數(shù)字從正常展示區(qū)域向上移動一定距離,新數(shù)字從下向上移動一定距離到達正常展示區(qū)域。如果個位數(shù)遞減至0,則十位數(shù)需要遞減,所以變化是十位和個位一起移動。
具體的實現(xiàn)思路為:
1、將時/分/秒的兩位數(shù)當成一個數(shù)字滾動組件;
2、將數(shù)字滾動組件的兩位數(shù),拆分成一個數(shù)字數(shù)組,變化操作針對數(shù)組中的單個元素操作即可;
3、保存舊數(shù)字,將舊數(shù)字和新數(shù)字的數(shù)組元素逐個比較,數(shù)字相同的位繪制新數(shù)字,數(shù)字不同的位一起移動即可;
4、在移動數(shù)字時,需要將舊數(shù)字向上移動,移動的距離是 0 至 負的最大滾動距離;同時要將新數(shù)字向上移動,移動距離為最大滾動距離 至 0;其中最大滾動距離是數(shù)字滾動控件的高度,該值需要根據(jù)實際的UI稿確定。
倒計時滾動組件繼承自TextView,在構(gòu)造函數(shù)中設(shè)置【最大滾動距離】和【畫筆相關(guān)屬性】,這兩者都需要根據(jù)實際UI稿確定。
其中,最大滾動距離mMaxMoveHeight是UI稿中時/分/秒數(shù)字控件的整體高度;畫筆設(shè)置的字體顏色、大小等,均為UI稿中時/分/秒數(shù)字的字體顏色、大小等。具體代碼如下所示:
//構(gòu)造函數(shù) public NumberFlipView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); mResources = context.getResources(); //最大滾動高度18dp mMaxMoveHeight = mResources.getDimensionPixelSize(R.dimen.qb_px_18); //設(shè)置畫筆相關(guān)屬性 setPaint(); } //設(shè)置畫筆相關(guān)屬性 private void setPaint() { //設(shè)置繪制數(shù)字為白色 mPaint.setColor(Color.WHITE); //設(shè)置繪制數(shù)字樣式為實心 mPaint.setStyle(Paint.Style.FILL); //設(shè)置繪制數(shù)字字體加粗 mPaint.setFakeBoldText(true); //設(shè)置繪制文字大小14dp mPaint.setTextSize(mResources.getDimensionPixelSize(R.dimen.qb_px_14)); }
繪制倒計時數(shù)字是通過重寫onDraw()實現(xiàn)的。首先拆分舊數(shù)字和新數(shù)字成為相應(yīng)的數(shù)字數(shù)組;
具體代碼如下所示:
//拆分新數(shù)字成為新數(shù)字數(shù)組 for (int i = 0; i < mNewNumber.length(); i++) { mNewNumberArray.add(String.valueOf(mNewNumber.charAt(i))); } //拆分老數(shù)字成為老數(shù)字數(shù)組 for (int i = 0; i < mOldNumber.length(); i++) { mOldNumberArray.add(String.valueOf(mOldNumber.charAt(i))); }
然后繪制數(shù)字:繪制新數(shù)字時,逐位判斷舊數(shù)字和新數(shù)字是否相同,如果數(shù)字相同,直接繪制新數(shù)字;如果數(shù)字不相同,舊數(shù)字和新數(shù)字均需要移動。
具體代碼如下所示:
//兩位數(shù)的newNumber的文字寬度 int textWidth = mResources.getDimensionPixelSize(R.dimen.qb_px_16); float curTextWidth = 0; for (int i = 0; i < mNewNumberArray.size(); i++) { //newNumber中每個數(shù)字的邊界 mPaint.getTextBounds(mNewNumberArray.get(i), 0, mNewNumberArray.get(i).length(), mTextRect); //newNumber中每個數(shù)字的寬度 int numWidth = mResources.getDimensionPixelSize(R.dimen.qb_px_5); //逐位判斷舊數(shù)字和新數(shù)字是否相同 if (mNewNumberArray.get(i).equals(mOldNumberArray.get(i))) { //數(shù)字相同,直接繪制新數(shù)字 canvas.drawText(mNewNumberArray.get(i), getWidth() * ONE_HALF - textWidth * ONE_HALF + curTextWidth, getHeight() * ONE_HALF + mTextRect.height() * ONE_HALF, mPaint); } else { //數(shù)字不相同,舊數(shù)字和新數(shù)字均需要移動 canvas.drawText(mOldNumberArray.get(i), getWidth() * ONE_HALF - textWidth * ONE_HALF + curTextWidth, mOldNumberMoveHeight + getHeight() * ONE_HALF + mTextRect.height() * ONE_HALF, mPaint); canvas.drawText(mNewNumberArray.get(i), getWidth() * ONE_HALF - textWidth * ONE_HALF + curTextWidth, mNewNumberMoveHeight + getHeight() * ONE_HALF + mTextRect.height() * ONE_HALF, mPaint); } curTextWidth += (numWidth + mResources.getDimensionPixelSize(R.dimen.qb_px_3));
getWidth()獲取的是倒計時控件的整個寬度;textWidth是兩位數(shù)字的寬度;numWidth是單個數(shù)字的寬度;curTextWidth是每個數(shù)字水平起始繪制位置的間距,curTextWidth=numWidth+兩個數(shù)字之間的間距。
十位數(shù)字的水平繪制起始位置為getWidth()/2 + textWidth/2;個位數(shù)字的水平繪制起始位置為getWidth()/2textWidth/2 + curTextWidth。getHight()獲取的是倒計時控件的整個高度;textRect.height()獲取的是數(shù)字的高度。
舊數(shù)字的垂直繪制起始位置為mOldNumberMoveHeight + getHeight()/2 + textRect.height()/2;新數(shù)字的垂直繪制起始位置為mNewNumberMoveHeightgetHeight()/2 + textRect.height()/2。
舊數(shù)字和新數(shù)字的滾動效果是通過ValueAnimator不斷改變舊數(shù)字的滾動距離mOldNumberMoveHeight和新數(shù)字的滾動距離mNewNumberMoveHeight實現(xiàn)的。
在規(guī)定的動畫時間FLIP_NUMBER_DURATION內(nèi),mNewNumberMoveHeight需要從最大滾動距離mMaxMoveHeight變?yōu)?,mOldNumberMoveHeight需要從0變?yōu)樨摰淖畲鬂L動距離mMaxMoveHeight;每次計算出新的滾動距離后,調(diào)用invalidate()方法,觸發(fā)onDraw()方法,不斷地繪制舊數(shù)字和新數(shù)字,以實現(xiàn)數(shù)字滾動的效果。
具體代碼如下所示:
/* 利用ValueAnimator,在規(guī)定時間FLIP_NUMBER_DURATION之內(nèi),將值從MAX_MOVE_HEIGHT變?yōu)?, 每次值變化都賦給mNewNumberMoveHeight,同時將mNewNumberMoveHeight - MAX_MOVE_HEIGHT的值賦給mOldNumberMoveHeight, 并重新繪制,實現(xiàn)新數(shù)字和舊數(shù)字的上滑; */ mNumberAnimator = ValueAnimator.ofFloat(mMaxMoveHeight, 0); mNumberAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mNewNumberMoveHeight = (float) animation.getAnimatedValue(); mOldNumberMoveHeight = mNewNumberMoveHeight - mMaxMoveHeight; invalidate(); } }); mNumberAnimator.setDuration(FLIP_NUMBER_DURATION); mNumberAnimator.start();
首先在布局中引入,用法和TextView相同。下圖為時、分、秒對應(yīng)的布局:
然后通過id找到對應(yīng)的倒計時數(shù)字控件:
mHourTextView = findViewById(R.id.hours_tv); mMinTextView = findViewById(R.id.min_tv); mSecondTextView = findViewById(R.id.sec_tv);
最后調(diào)用時/分/秒倒計時數(shù)字控件的方法,設(shè)置倒計時初始值或者倒計時新數(shù)字。如果是首次進行倒計時,需要調(diào)用setInitialNumber()方法設(shè)置初始值;否則調(diào)用flipNumber()方法設(shè)置新的倒計時數(shù)值。
具體用法如下所示:
if (mFirstSetTimer) { mHourTextView.setInitialNumber(hours); mMinTextView.setInitialNumber(minute); mSecondTextView.setInitialNumber(second); mFirstSetTimer = false; } else { mHourTextView.flipNumber(hours); mMinTextView.flipNumber(minute); mSecondTextView.flipNumber(second); }
在實現(xiàn)中,倒計時控件是作為ListView的子元素,而且ListView是處于一個Fragment中。
為了減少功耗,需要在倒計時控件不在可見范圍內(nèi)時,暫停倒計時;當?shù)褂嫊r控件重新出現(xiàn)在可見范圍內(nèi)時,重新開始倒計時。下圖是倒計時暫停與開始的場景。
頁面滑動,倒計時控件滑出可視區(qū)域,當?shù)褂嫊r控件滑出ListView的可視范圍內(nèi),需要暫停倒計時。該情況的重點是:需要判斷出子view是否已經(jīng)移出ListView中。
如果應(yīng)用只需要兼容安卓7及以上,可以通過重寫onDetachedFromWindow()方法,在方法體內(nèi)進行取消倒計時的操作。因為每當子view移出ListView時就會調(diào)用這個方法。
@Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); //移出屏幕調(diào)用,暫停倒計時 stopCountDownTimerAndAnimation(); }
如果應(yīng)用需要兼容安卓7以下,則上述方法會失效,因為onDetachedFromWindow()方法并不兼容低版本。但是可是通過重寫onStartTemporaryDetach()方法實現(xiàn)相同的效果。
@Override public void onStartTemporaryDetach() { super.onStartTemporaryDetach(); //移出屏幕調(diào)用,暫停倒計時 stopCountDownTimerAndAnimation(); }
通過tab切換到其他Fragment
當?shù)褂嫊r控件位于可視范圍內(nèi),此時通過tab切換到其他Fragment時,需要暫停倒計時。該情況下倒計時控件所在的Fragment會隱藏,可以在Fragment隱藏時獲取倒計時控件的View,然后調(diào)用其方法暫停倒計時。
@Override public void onFragmentHide() { super.onFragmentHide(); //暫停倒計時 stopNewArrivalCountDownTimerAndAnimation(); }
為了獲取倒計時控件所在的View對象,通過遍歷ListView可視范圍內(nèi)的子View,判斷其是否是倒計時控件所在的View對象。然后調(diào)用倒計時控件所在View對象的stopCountDownTimerAndAnimation()方法,暫停倒計時。
/** * 獲取倒計時控件所在的view對象,暫停倒計時 */ private void stopNewArrivalCountDownTimerAndAnimation() { if (mListView != null) { for (int index = 0; index < mListView.getChildCount(); index++) { View view = mListView.getChildAt(index); if (view instanceof HomeItemViewNewArrival) { ((HomeItemViewNewArrival) view).stopCountDownTimerAndAnimation(); } } } }
應(yīng)用切換至后臺/跳轉(zhuǎn)到其他界面
當?shù)褂嫊r控件位于可視范圍內(nèi),此時應(yīng)用切換到至后臺 或者 點擊倒計時控件所在界面的其他內(nèi)容,跳轉(zhuǎn)到其他界面,都需要暫停倒計時。由于這些情況都會觸發(fā)倒計時所在Fragment的onStop()方法。因此可以重寫onStop(),并在該方法體內(nèi)獲取倒計時控件的View,然后暫停倒計時。
stopNewArrivalCountDownTimerAndAnimation()方法同上。
@Override public void onStop() { super.onStop(); //暫停倒計時 stopNewArrivalCountDownTimerAndAnimation(); }
頁面滑動,倒計時控件滑入可視區(qū)域
當?shù)褂嫊r控件滑出可視區(qū)域后,再次滑入可視區(qū)域,會自動調(diào)用Adapter的getView()方法,然后調(diào)用倒計時控件的onBindView()方法。由于onBindView()方法中會初始化倒計時控件,因此該情況下,無需再手動開始倒計時。
通過tab切換回到倒計時所在的Fragment
通過tab切換回到倒計時控件所在的Fragment,若此時倒計時控件在可視范圍內(nèi),則需要重新開始倒計時。由于該情況下Fragment會重新顯示,因此可以在Fragment顯示時獲取倒計時控件的View,然后調(diào)用其方法重新開始倒計時。
@Override public void onFragmentShow(int source, int floor) { super.onFragmentShow(source, floor); //重新開始倒計時 refreshNewArrival(); }
同樣,為了獲取倒計時控件所在的View對象,需要通過遍歷ListView可視范圍內(nèi)的子View,判斷其是否是倒計時控件所在的View對象。然后調(diào)用倒計時控件所在View對象的refreshEventStatus ()方法,開始倒計時。
/** * 獲取倒計時控件所在的view對象,開始倒計時 */ private void refreshNewArrival() { if (mListView != null) { for (int index = 0; index < mListView.getChildCount(); index++) { View view = mListView.getChildAt(index); if (view instanceof HomeItemViewNewArrival) { ((HomeItemViewNewArrival) view).refreshEventStatus(); } } } }
應(yīng)用切換回前臺/從其他界面回退
當應(yīng)用切換到回前臺 或者 從其他界面回退到倒計時控件所在的界面,若此時倒計時控件在可視范圍內(nèi),則都需要重新開始倒計時。由于這些情況都會觸發(fā)倒計時所在Fragment的onResume()方法。因此可以重寫onResume(),并在該方法體內(nèi)獲取倒計時控件的View,然后調(diào)用其方法重新開始倒計時。
其中refreshNewArrival()方法同上。
@Override public void onResume() { super.onResume(); //重新開始倒計時 refreshNewArrival(); }
“如何實現(xiàn)與優(yōu)化搶購倒計時自定義控件”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!