Android自定義View實(shí)現(xiàn)APP啟動(dòng)頁倒計(jì)時(shí)效果
Android自定義View實(shí)現(xiàn)APP啟動(dòng)頁倒計(jì)時(shí)效果,供大家參考,具體內(nèi)容如下
之前也是做過APP啟動(dòng)頁的倒計(jì)時(shí)效果,但是只有文字變化,沒有動(dòng)畫效果,這次通過使用自定義View控件來制作一個(gè)帶有動(dòng)畫效果的倒計(jì)時(shí)。
倒計(jì)時(shí)效果的基本思路如下:
Canvas提供了繪制弧形的方法,drawArc(),使用這個(gè)方法通過定時(shí)刷新計(jì)算當(dāng)前弧形的角度,就可以模擬出倒計(jì)時(shí)的動(dòng)畫效果,同時(shí)借助drawText()方法可以實(shí)現(xiàn)倒計(jì)時(shí)文字。
(1)繼承View
(2)使用canvas的drawArc()來繪制弧形,模擬動(dòng)畫效果
(3)使用canvas的drawText()來繪制倒計(jì)時(shí)文字
(4)向外部(Activity或者Fragment)提供接口,倒計(jì)時(shí)結(jié)束之后通過接口告訴外部
具體看代碼:
首先定義當(dāng)前view的寬度和高度的默認(rèn)值,并重寫onMeasure()方法,否則在布局文件中即使使用wrap_content當(dāng)前view也會(huì)布滿全屏
?//當(dāng)前view高度和寬度的默認(rèn)值 ?private static final int DEFAULT_WIDTH = 100; ?private static final int DEFAULT_HEIGHT = 100;
定義三個(gè)變量,分別是倒計(jì)時(shí)總長度,當(dāng)前剩余倒計(jì)時(shí)長度,以及剩余時(shí)間比例,根據(jù)這個(gè)比例繪制弧形劃過的角度
private int countDownTime = 5000;//倒計(jì)時(shí)的時(shí)間,默認(rèn)是5秒 private int countDownNow = 5000;//當(dāng)前的時(shí)間,默認(rèn)也是5秒 private float timeTatio = 1f;//剩余時(shí)間比例,默認(rèn)為1
定義畫筆以及向外部提供的接口
使用Android提供的倒計(jì)時(shí)類,如果不使用這個(gè)類,也可以通過thread+handler實(shí)現(xiàn),初始化這個(gè)類需要傳入兩個(gè)參數(shù),第一個(gè)參數(shù)是倒計(jì)時(shí)總長度,第二個(gè)參數(shù)是倒計(jì)時(shí)間隔,也就是每隔多長時(shí)間停止一次。這個(gè)類重寫了兩個(gè)方法,第一個(gè)方法是倒計(jì)時(shí)暫停的時(shí)候需要執(zhí)行的操作,第二個(gè)方法是倒計(jì)時(shí)完全結(jié)束之后需要執(zhí)行的操作,在這里,我設(shè)置了每隔10ms暫停一次,計(jì)算剩余時(shí)間的比例并重新繪制整個(gè)view,倒計(jì)時(shí)完全結(jié)束后通過接口告訴外部。
private Paint paint; ? ? private ViewCountDownFinishListener viewCountDownFinishListener; ? ? //倒計(jì)時(shí),每隔100毫秒倒計(jì)時(shí)一次 ? ? private CountDownTimer countDownTimer = new CountDownTimer(countDownTime,10) { ? ? ? ? @Override ? ? ? ? public void onTick(long l) { ? ? ? ? ? ? LogUtils.logI("倒計(jì)時(shí):"+l); ? ? ? ? ? ? countDownNow = (int) l; ? ? ? ? ? ? //計(jì)算比例 ? ? ? ? ? ? timeTatio = (float) countDownNow / (float)countDownTime; ? ? ? ? ? ? invalidate(); ? ? ? ? } ? ? ? ? @Override ? ? ? ? public void onFinish() { ? ? ? ? ? ? countDownTimer.cancel(); ? ? ? ? ? ? if(viewCountDownFinishListener != null){ ? ? ? ? ? ? ? ? viewCountDownFinishListener.countDownFinish(); ? ? ? ? ? ? } ? ? ? ? } ? ? };
在構(gòu)造方法中調(diào)用init()方法以啟動(dòng)倒計(jì)時(shí)
private void init(){ ? ? ? ? if(countDownTimer != null) { ? ? ? ? ? ? countDownTimer.start(); ? ? ? ? } ? ? }
//設(shè)置倒計(jì)時(shí)完成的接口 ? ? public void setViewCountDownFinishListener(ViewCountDownFinishListener viewCountDownFinishListener){ ? ? ? ? this.viewCountDownFinishListener = viewCountDownFinishListener; ? ? }
重寫onDraw()方法,根據(jù)
canvas.drawArc(float left,float top,float right,float bottom,float startAngle,float sweepAngle,boolean useCenter, Paint paint)
參數(shù)說明:
前四個(gè)參數(shù)表明當(dāng)前的弧形所在的橢圓,只要設(shè)置橢圓寬度和高度一樣,就是一個(gè)圓了,
startAngle是開始繪制的角度,以正右方向(X軸正方向)為0都,順時(shí)針為正度數(shù),逆時(shí)針為負(fù)度數(shù),這里我設(shè)置從-90°(也就是Y軸負(fù)方向)開始,
sweep是指弧形劃過的角度,這里我設(shè)置的是從0開始一直劃過360度,剛好畫一個(gè)圓,但是其實(shí)并沒有完全到360度,因?yàn)槲以O(shè)置了每隔10ms執(zhí)行一次,最后并不會(huì)完全是360度,但是非常接近,幾乎看不出來。
useCenter表示是否連接到圓心,如果連接到圓心,就是扇形,這里需要弧形,就選擇false
繪制完弧形后開始繪制倒計(jì)時(shí)文字,這個(gè)比較簡單,就是計(jì)算倒計(jì)時(shí)剩余時(shí)間就可以了,然后繪制出來。
protected void onDraw(Canvas canvas) { ? ? ? ? LogUtils.logI("onDraw()方法執(zhí)行"); ? ? ? ? super.onDraw(canvas); ? ? ? ? paint = new Paint(); ? ? ? ? paint.setStyle(Paint.Style.STROKE); ? ? ? ? paint.setColor(Color.BLACK); ? ? ? ? paint.setAntiAlias(true); ? ? ? ? paint.setStrokeWidth(2); ? ? ? ? paint.setAntiAlias(true); ? ? ? ? //根據(jù)比例繪制一個(gè)扇形,也就是一個(gè)圓形 ? ? ? ? //當(dāng)前的弧度 ? ? ? ? float currentRadian = 360 - 360 * timeTatio; ? ? ? ? canvas.drawArc(10,10,60,60,-90,currentRadian,false,paint); ? ? ? ? //繪制文字 ? ? ? ? paint.reset(); ? ? ? ? paint.setStyle(Paint.Style.FILL); ? ? ? ? paint.setColor(Color.parseColor("#3399ff")); ? ? ? ? paint.setAntiAlias(true); ? ? ? ? paint.setTextSize(30); ? ? ? ? canvas.drawText(String.valueOf((int) (countDownNow/1000)),27,45,paint); ? ? }
重寫onMeasure()方法,為了將View顯示在正確的位置上。
//重寫onMeasure方法 ? ? @Override ? ? protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ? ? ? ? //super.onMeasure(widthMeasureSpec, heightMeasureSpec); ? ? ? ? setMeasuredDimension(measureSpecHandler(widthMeasureSpec,DEFAULT_WIDTH),measureSpecHandler(heightMeasureSpec,DEFAULT_HEIGHT)); ? ? } ? ? //計(jì)算高度和寬度的具體值 ? ? private int measureSpecHandler(int measureSpec,int defaultSize){ ? ? ? ? int result = defaultSize; ? ? ? ? int specModel = MeasureSpec.getMode(measureSpec); ? ? ? ? int specSize = MeasureSpec.getSize(measureSpec); ? ? ? ? switch(specModel){ ? ? ? ? ? ? case MeasureSpec.EXACTLY: ? ? ? ? ? ? ? ? result = specSize; ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case MeasureSpec.AT_MOST: ? ? ? ? ? ? ? ? result = Math.min(result,specSize); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? default: ? ? ? ? ? ? ? ? result = defaultSize; ? ? ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? return result; ? ? }
定義接口,向外部提供倒計(jì)時(shí)完成的通知信息
?//定義一個(gè)接口,當(dāng)?shù)褂?jì)時(shí)完成之后通知activity做出相應(yīng)改變 ? ? public interface ViewCountDownFinishListener{ ? ? ? ? void countDownFinish(); ? ? }
在xml中直接使用:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" ? ? xmlns:app="http://schemas.android.com/apk/res-auto" ? ? xmlns:tools="http://schemas.android.com/tools" ? ? android:layout_width="match_parent" ? ? android:layout_height="match_parent" ? ? tools:context="com.fanjuan.project.wisdomclass.activity.ActivityMain"> ? ? <com.fanjuan.project.wisdomclass.view.CountDownView ? ? ? ? android:id="@+id/cv_count_down" ? ? ? ? android:layout_width="wrap_content" ? ? ? ? android:layout_height="wrap_content" ? ? ? ? android:layout_gravity="right" ? ? ? ? android:layout_marginRight="20dp" ? ? ? ? android:layout_marginTop="20dp" /> </FrameLayout>
在activity中使用:
?protected void initView() { ? ? ? ? countDownView = findViewById(R.id.cv_count_down); ? ? } ? ? @Override ? ? protected void initListener() { ? ? ? ? super.initListener(); ? ? ? ? countDownView.setViewCountDownFinishListener(new CountDownView.ViewCountDownFinishListener() { ? ? ? ? ? ? @Override ? ? ? ? ? ? public void countDownFinish() { ? ? ? ? ? ? ? ? ToastUtils.toastInfo("倒計(jì)時(shí)結(jié)束"); ? ? ? ? ? ? } ? ? ? ? }); ? ? }
最后的效果:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 消息分發(fā)使用EventBus的實(shí)例詳解
這篇文章主要介紹了Android 消息分發(fā)使用EventBus的實(shí)例詳解的相關(guān)資料,在項(xiàng)目中用了許多Handler和broadcast導(dǎo)致代碼冗余,顯得雜亂無章,這里使用EventBus來實(shí)現(xiàn)相同的功能,需要的朋友可以參考下2017-07-07Android UI動(dòng)態(tài)設(shè)置帶有Stroke漸變色背景Drawable
這篇文章主要為大家介紹了Android UI動(dòng)態(tài)設(shè)置帶有Stroke漸變色背景Drawable,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01android getActivity.findViewById獲取ListView 返回NULL的方法
下面小編就為大家?guī)硪黄猘ndroid getActivity.findViewById獲取ListView 返回NULL的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11Android UI之ImageView實(shí)現(xiàn)圖片旋轉(zhuǎn)和縮放
這篇文章主要介紹了Android UI之ImageView實(shí)現(xiàn)圖片旋轉(zhuǎn)和縮放的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-09-09Android開發(fā)新手常見的10個(gè)誤區(qū)
這篇文章主要介紹了Android開發(fā)新手常見的10個(gè)誤區(qū),我們?nèi)匀豢吹搅四男┬碌腁ndr​​oid開發(fā)人員不斷重復(fù)的錯(cuò)誤,這里有10個(gè)最常見的誤區(qū),需要的朋友可以參考下2015-03-03Android使用ftp方式實(shí)現(xiàn)文件上傳和下載功能
這篇文章主要介紹了Android使用ftp方式實(shí)現(xiàn)文件上傳和下載功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06