自定義View( 啟動(dòng)頁(yè)倒計(jì)時(shí))

項(xiàng)目需要在啟動(dòng)頁(yè)加上倒計(jì)時(shí)的功能,所以自定義了一個(gè)倒計(jì)時(shí)的View,下面的是具體的分析

1糖赔、自定義View的基礎(chǔ)

一般情況下,自定義View可以有三種方式轩端,
第一種:就是繼承View或者ViewGroup來(lái)自己從頭開(kāi)始實(shí)現(xiàn)放典,
第二種:就是繼承系統(tǒng)已經(jīng)實(shí)現(xiàn)了特定功能的View或者ViewGroup,例如TextView基茵,ImageView奋构,LinearLayout等等,這樣做的原因和好處就是拱层,可以繼承部分功能弥臼,在此基礎(chǔ)上再進(jìn)行自己需要的擴(kuò)展
第三種:就是利用布局將一些View進(jìn)行特定的組合來(lái)組成一個(gè)復(fù)合的組件

2、倒計(jì)時(shí)View的具體實(shí)現(xiàn)

因?yàn)楸疚牡慕M件是使用第一種方式進(jìn)行實(shí)現(xiàn)的根灯,所以下面就是結(jié)合代碼對(duì)第一種的實(shí)現(xiàn)方式進(jìn)行分析径缅,代碼如下

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CountDownView">
        <attr name="arc_circle_color" format="color"/>
        <attr name="in_circle_color" format="color"/>
        <attr name="txt_time_color" format="color"/>
    </declare-styleable>
</resources>

上面的代碼是自定義的屬性,它放在values/attr.xml文件中烙肺,當(dāng)然這個(gè)attr.xml文件需要我們自己創(chuàng)建纳猪,它的主要目的就是使我們可以在xml文件中進(jìn)行屬性的設(shè)置,如果自己實(shí)現(xiàn)的自定義View中沒(méi)有自定義的屬性茬高,則這個(gè)可以忽略

public class CountDownView extends View {
     //繪制內(nèi)圓的畫(huà)筆對(duì)象
    private Paint mInCirclePaint = new Paint();
    //繪制文字的畫(huà)筆對(duì)象
    private Paint mTxtPaint = new Paint();
    //繪制圓弧的畫(huà)筆對(duì)象
    private Paint mArcPaint = new Paint();

    //計(jì)時(shí)類(lèi)
    private Timer mTimer = null;
    //外部圓當(dāng)前繪制的弧度
    private int currentAngle = 360;
    //外部圓最終繪制的弧度
    private int progress = 0;
    //當(dāng)前的描述兆旬,這里默認(rèn)為4秒,不可修改
    private int currentMillon = 4;

    //外部圓的背景顏色
    private int arcCircleColor;
    //內(nèi)部圓的背景顏色
    private int inCircleColor;
    //文字的顏色
    private int txtTimeColor;
    
    ..............
}

以上是需要用到的屬性怎栽,代碼中都有詳細(xì)的注釋了

public class CountDownView extends View {

    .......

    public CountDownView(Context context) {
        this(context, null);
    }


    public CountDownView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }


    public CountDownView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CountDownView,
                defStyleAttr, 0);
        arcCircleColor = a.getColor(R.styleable.CountDownView_arc_circle_color, Color.RED);
        inCircleColor = a.getColor(R.styleable.CountDownView_in_circle_color, Color.parseColor
                ("#FFB7B6B6"));
        txtTimeColor = a.getColor(R.styleable.CountDownView_txt_time_color, Color.WHITE);
        a.recycle();
        init();
    }

    private void init() {
        mTimer = new Timer();
    }
    ......
}

接下來(lái)是三個(gè)構(gòu)造函數(shù),這里是最先被初始化的地方宿饱,所以在這里我們要把在attr.xml文件中的自定義屬性取出來(lái)熏瞄,并且設(shè)置默認(rèn)值

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width = 0;
        int height = 0;

        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = (int) ViewUtils.dp2px(50);
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            if (getLayoutParams().height == WindowManager.LayoutParams.WRAP_CONTENT) {
                height = (int) ViewUtils.dp2px(50);
            } else {
                height = heightSize;
            }
        }

        if (width <= height) {
            setMeasuredDimension(width, width);
        } else {
            setMeasuredDimension(height, height);
        }
    }

接下來(lái)就是自定義View中比較重要的一個(gè)方法,這個(gè)方法的主要作用就是測(cè)量谬以,它的兩個(gè)傳入的參數(shù)分別是由父布局測(cè)量后傳遞下來(lái)的測(cè)量寬度和測(cè)量高度强饮,這個(gè)測(cè)量寬度包括了寬度的大小和測(cè)量模式,而測(cè)量高度也是一樣为黎。這個(gè)方法的主要作用就是測(cè)量View的大小邮丰,如果說(shuō)自定義View是畫(huà)畫(huà)的話(huà),那么這個(gè)方法就是先測(cè)量出一塊畫(huà)布的大小铭乾,以便我們后續(xù)在這個(gè)畫(huà)布上進(jìn)行作畫(huà)

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //獲取屏幕的寬度
        int width = getMeasuredWidth();
        //獲取屏幕的高度
        int height = getMeasuredHeight();
        //繪制內(nèi)部的圓
        mInCirclePaint.setStyle(Paint.Style.FILL);
        mInCirclePaint.setAntiAlias(true);
        mInCirclePaint.setColor(inCircleColor);
        canvas.drawCircle(width / 2, height / 2, width / 2 - 10, mInCirclePaint);

        //繪制文字
        int mTxtSize = (int) ViewUtils.dp2px(14);
        mTxtPaint.setTextSize(mTxtSize);
        Rect mBound = new Rect();
        mTxtPaint.getTextBounds(String.valueOf(currentMillon), 0, String.valueOf(currentMillon)
                .length(), mBound);
        mTxtPaint.setColor(txtTimeColor);
        canvas.drawText(String.valueOf(currentMillon), width / 2 - mBound.width() / 2, height / 2
                + mBound.height() / 2, mTxtPaint);

        // 繪制圓弧
        mArcPaint.setStrokeWidth(10);
        mArcPaint.setStyle(Paint.Style.STROKE);
        mArcPaint.setAntiAlias(true);
        mArcPaint.setColor(arcCircleColor);
        RectF rect = new RectF(10, 10, width - 10, height - 10);
        canvas.drawArc(rect, -90, currentAngle, false, mArcPaint);

    }

這個(gè)方法是自定義View中的另一個(gè)比較重要的方法剪廉,它的主要作用就是繪制具體的內(nèi)容,在這個(gè)方法里面炕檩,我們會(huì)持有畫(huà)布的對(duì)象斗蒋,因此我們可以利用系統(tǒng)提供的api來(lái)繪制出你想要的圖形,上面的代碼就繪制了一個(gè)圓,文字泉沾,圓弧捞蚂。那這一步就相當(dāng)于作畫(huà)中的在畫(huà)布上畫(huà)畫(huà)了。

3跷究、最后一步

經(jīng)過(guò)前面的代碼姓迅,我們可以繪制出倒計(jì)時(shí)View的大致的樣子,但是怎樣實(shí)現(xiàn)倒計(jì)時(shí)呢俊马,代碼如下:

 /**
     * 動(dòng)畫(huà)開(kāi)始
     */
    public void start() {
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                postInvalidate();
                if (currentAngle <= progress) {
                    //到這里队贱,自動(dòng)執(zhí)行的任務(wù)已經(jīng)結(jié)束,在這里我們可以定義回調(diào)接口來(lái)進(jìn)行特定的處理
                    mTimer.cancel();
                } else {
                    currentAngle -= 5;
                }
                if (currentAngle % 90 == 0 && currentMillon > 0) {
                    currentMillon--;
                }
            }
        }, 50, 50);
    }

以上的代碼就是倒計(jì)時(shí)之行的關(guān)鍵潭袱,它主要是這樣的柱嫌,在onDraw方法中先在外部繪制出一個(gè)圓滿(mǎn)的圓形,但是繪制的弧度(currentAngle)是一個(gè)變量屯换,我們?cè)诙〞r(shí)任務(wù)中不斷將這個(gè)變量進(jìn)行自減编丘,并且進(jìn)行View的重繪(通過(guò)postInvalidate()方法),這樣就可以實(shí)現(xiàn)圓形圖案縮減的動(dòng)畫(huà)了彤悔。另外嘉抓,上面代碼中的秒數(shù)的計(jì)算只是我粗略的計(jì)算,并不算準(zhǔn)確晕窑,有興趣可以實(shí)現(xiàn)更佳精確的計(jì)算方法

以上就是該View的全部實(shí)現(xiàn)過(guò)程抑片,這是一個(gè)簡(jiǎn)單的自定義View,并沒(méi)有涉及到很多其它復(fù)雜的操作杨赤,但是大致的流程都是這個(gè)樣子的敞斋,只是可能在實(shí)現(xiàn)過(guò)程中會(huì)需要結(jié)合其他知識(shí)來(lái)進(jìn)行更復(fù)雜的View的定制,最后疾牲,自定義View植捎,講究一步一步實(shí)現(xiàn),我們并不能一步到位地實(shí)現(xiàn)一個(gè)很復(fù)雜的View阳柔,因此焰枢,我建議可以先實(shí)現(xiàn)你要定制的View的大致輪廓,然后再根據(jù)具體的需求對(duì)這個(gè)輪廓進(jìn)行更加細(xì)節(jié)的實(shí)現(xiàn)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末舌剂,一起剝皮案震驚了整個(gè)濱河市济锄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌霍转,老刑警劉巖荐绝,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谴忧,居然都是意外死亡很泊,警方通過(guò)查閱死者的電腦和手機(jī)角虫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)委造,“玉大人戳鹅,你說(shuō)我怎么就攤上這事』枵祝” “怎么了枫虏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)爬虱。 經(jīng)常有香客問(wèn)我隶债,道長(zhǎng),這世上最難降的妖魔是什么跑筝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任死讹,我火速辦了婚禮,結(jié)果婚禮上曲梗,老公的妹妹穿的比我還像新娘赞警。我一直安慰自己,他們只是感情好虏两,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布愧旦。 她就那樣靜靜地躺著,像睡著了一般定罢。 火紅的嫁衣襯著肌膚如雪笤虫。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天祖凫,我揣著相機(jī)與錄音琼蚯,去河邊找鬼。 笑死蝙场,一個(gè)胖子當(dāng)著我的面吹牛凌停,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播售滤,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼台诗!你這毒婦竟也來(lái)了完箩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拉队,失蹤者是張志新(化名)和其女友劉穎弊知,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體粱快,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秩彤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年叔扼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漫雷。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓜富,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出降盹,到底是詐尸還是另有隱情与柑,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布蓄坏,位于F島的核電站价捧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏涡戳。R本人自食惡果不足惜结蟋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渔彰。 院中可真熱鬧嵌屎,春花似錦、人聲如沸胳岂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乳丰。三九已至掌测,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間产园,已是汗流浹背汞斧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留什燕,地道東北人粘勒。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像屎即,于是被迫代替她去往敵國(guó)和親庙睡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容