Android筆記自訂View之製作錶盤介面

來源:互聯網
上載者:User

標籤:菜鳥   重寫   http   iss   attrs   公眾   .property   ack   styleable   

前言

      最近我跟自訂View杠上了,甚至說有點上癮到走火入魔了。身為菜鳥的我自然要查閱大量的資料,學習大神們的代碼,這不,前兩天正好在郭神在公眾號裡推送一片自訂控制項的文章——一步步實現精美的鐘錶介面。正適合我這種菜鳥來學習,閑著沒事,我就差不多依葫蘆畫瓢也寫了一個自訂表格盤View,現在純粹最為筆記記錄下來。先展示下:



下面進入正題

自訂表格盤屬性

          老規矩,先在attrs檔案裡添加錶盤自訂屬性

    <declare-styleable name="WatchView">        <attr name="watchRadius" format="dimension"/>                     //錶盤半徑        <attr name="watchPadding" format="dimension"/>                    //錶盤相對控制項邊框距離        <attr name="watchScalePadding" format="dimension"/>               //刻度相對錶盤距離        <attr name="watchScaleColor" format="color|reference"/>           //常規刻度顏色        <attr name="watchScaleLength" format="dimension|reference"/>      //常規刻度長度        <attr name="watchHourScaleColor" format="dimension|reference"/>   //整點刻度顏色        <attr name="watchHourScaleLength" format="dimension|reference"/>  //整點刻度長度        <attr name="hourPointColor" format="color|reference"/>            //時針顏色        <attr name="hourPointLength" format="dimension|reference"/>       //時針長度        <attr name="minutePointColor" format="color|reference"/>          //分針顏色        <attr name="minutePointLength" format="dimension|reference"/>     //分針長度        <attr name="secondPointColor" format="color|reference"/>          //秒針顏色        <attr name="secondPointLength" format="dimension|reference"/>     //秒針長度        <attr name="timeTextSize" format="dimension|reference"/>          //錶盤字型大小        <attr name="timeTextColor" format="color|reference"/>             //錶盤字型顏色    </declare-styleable>

在自訂View的構造方法種擷取自訂屬性

先將屬性變數聲明如下:

<span style="font-size:14px;">    /**錶盤邊距*/    private float mWatchPadding = 5;    /**錶盤與刻度邊距*/    private float mWatchScalePadding = 5;    /**錶盤半徑*/    private float mWatchRadius = 250;    /**錶盤刻度長度*/    private float mWatchScaleLength;    /**錶盤刻度顏色*/    private int mWatchScaleColor = Color.BLACK;    /**錶盤整點刻度長度*/    private float mHourScaleLength = 8;    /**錶盤整點刻度顏色*/    private int mHourScaleColor = Color.BLUE;    /**錶盤時針顏色*/    private int mHourPointColor = Color.BLACK;    /**錶盤時針長度*/    private float mHourPointLength = 100;    /**錶盤分針顏色*/    private int mMinutePointColor = Color.BLACK;    /**錶盤分針長度*/    private float mMinutePointLength = 130;    /**錶盤秒針顏色*/    private int mSecondPointColor = Color.RED;    /**錶盤秒針長度*/    private float mSecondPointLength = 160;    /**錶盤尾部指標長度*/    private float mEndPointLength;    /**錶盤數字顏色*/    private int mTimeTextColor = Color.BLACK;    /**錶盤數字大小*/    private int mTimeTextSize = 15;</span>

在構造方法種擷取自訂屬性

<span style="font-size:14px;">    public WatchView(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.WatchView);        int n = array.getIndexCount();        for (int i = 0;i<n;i++){            int attr = array.getIndex(i);            switch (attr){                case R.styleable.WatchView_watchRadius:                    mWatchRadius = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,60));                    break;                case R.styleable.WatchView_watchPadding:                    mWatchPadding = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,5));                    break;                case R.styleable.WatchView_watchScalePadding:                    mWatchScalePadding = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,3));                    break;                case R.styleable.WatchView_watchScaleLength:                    mWatchScaleLength = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,5));                    break;                case R.styleable.WatchView_watchScaleColor:                    mWatchScaleColor = array.getColor(attr, Color.parseColor("#50000000"));                    break;                case R.styleable.WatchView_watchHourScaleLength:                    mHourScaleLength = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,10));                    break;                case R.styleable.WatchView_watchHourScaleColor:                    mHourScaleColor = array.getColor(attr,Color.BLACK);                    break;                case R.styleable.WatchView_hourPointLength:                    mHourPointLength = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,35));                    break;                case R.styleable.WatchView_hourPointColor:                    mHourPointColor = array.getColor(attr,Color.BLACK);                    break;                case R.styleable.WatchView_minutePointLength:                    mMinutePointLength = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,40));                    break;                case R.styleable.WatchView_minutePointColor:                    mMinutePointColor = array.getColor(attr,Color.BLACK);                    break;                case R.styleable.WatchView_secondPointLength:                    mSecondPointLength = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,50));                    break;                case R.styleable.WatchView_secondPointColor:                    mSecondPointColor = array.getColor(attr,Color.BLUE);                    break;                case R.styleable.WatchView_timeTextSize:                    mTimeTextSize = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,15));                    break;                case R.styleable.WatchView_timeTextColor:                    mTimeTextColor = array.getColor(attr,Color.BLACK);                    break;            }        }        array.recycle();    }</span>

設定控制項大小

這裡當然就是重寫onMeasure方法啦,這裡我們處理的簡單點,如下面代碼所示,當我們將控制項的寬高都設定為wrap_content(即MeasureSpec.UNSPECIFED)時,我們將寬高設定為預設值(wrapContentSize)和圓盤半徑+圓盤邊距(mWatchRadius+mWatchPadding)之間取最大值,其他情況下就取系統自取值。當然作為一個嚴謹的控制項,僅僅這樣處理肯定是不行的。項目中,我們要根據我們的需求自行修改裡面的代碼以適配。

<span style="font-size:14px;">    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int wrapContentSize = 1000;        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        if (widthMode == MeasureSpec.UNSPECIFIED && heightMode == MeasureSpec.UNSPECIFIED){            wrapContentSize = (int) Math.max(wrapContentSize,mWatchRadius+mWatchPadding);            setMeasuredDimension(wrapContentSize,wrapContentSize);        }else {            setMeasuredDimension(widthSize,heightSize);        }    }</span>

重寫onDraw方法

來到最關鍵真正畫錶盤時刻了。一步一步來,首先初始化我們的畫筆(我的習慣,寫一個initPaint方法)

<span style="font-size:14px;">    private void initPaint(){        mPaint = new Paint();        mPaint.setAntiAlias(true);        mPaint.setColor(Color.WHITE);        mPaint.setStyle(Paint.Style.FILL);    }</span>
為了不顯贅述,方便理解,我直接展示代碼,在代碼中解釋

開畫之前我們先將畫筆移動到控制項中心點位置,如下:

<span style="font-size:14px;">@Override    protected void onDraw(Canvas canvas) {        canvas.translate(getWidth()/2,getHeight()/2);    }</span>
第一步,畫錶盤
<span style="font-size:14px;">    /**     * 畫錶盤     * @param canvas     */    private void paintWatchBoard(Canvas canvas){        initPaint();        canvas.save();        canvas.drawCircle(0,0,mWatchRadius,mPaint); //畫圓盤        canvas.restore();    }</span>
註:每次畫圖之前都要先調用canvas.save()方法,儲存畫筆屬性,畫完之後要調用canvas.restore()方法,重設畫筆屬性
這裡就不一一展示每次畫完之後的了。

第二步,畫刻度+整點時間數字(刻度從12點方向開始畫)

<span style="font-size:14px;">    /**     * 畫刻度及整點數字     * @param canvas     */    private void paintScale(Canvas canvas){        int lineLength; //刻度標記長度        canvas.save();        for (int i = 0;i<60;i++){            if (i%5 == 0){//整點刻度下畫筆相關屬性                mPaint.setStrokeWidth(MyUtil.dip2px(getContext(),1.5f));                mPaint.setColor(mHourScaleColor);                lineLength = MyUtil.dip2px(getContext(),8);                canvas.drawLine(0,-mWatchRadius+mWatchScalePadding,0,-mWatchRadius+mWatchScalePadding+lineLength,mPaint);                mPaint.setColor(mTimeTextColor);                mPaint.setTextSize(mTimeTextSize);                canvas.drawText(mTimes[i/5],-mTimeTextSize/2,-mWatchRadius+mWatchScalePadding + lineLength+mTimeTextSize,mPaint);//整點的位置標上整點時間數字            }else {//非整點刻度下畫筆相關屬性                mPaint.setStrokeWidth(MyUtil.dip2px(getContext(),0.8f));                mPaint.setColor(mWatchScaleColor);                lineLength = MyUtil.dip2px(getContext(),5);                canvas.drawLine(0,-mWatchRadius+mWatchScalePadding,0,-mWatchRadius+mWatchScalePadding+lineLength,mPaint);            }            canvas.rotate(6);//每次畫完一個刻度標記,畫筆順時針旋轉6度(360/60,相鄰兩刻度之間的角度差為6度)        }        canvas.restore();    }</span>
其中,整點數字我用了羅馬數字來表示

<span style="font-size:14px;">private String[] mTimes = {"XII","Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ","Ⅸ","Ⅹ","XI"};</span>

第三步,畫時針、分針、秒針以及其它修飾圖

考慮到時針、分針和秒針大小長度各不一樣,我這裡特意定義了三支畫筆來分別畫時針、分針和秒針。

同樣的,先初始化指標畫筆:

<span style="font-size:14px;">/**     * 初始化指標     */    private void initPointPaint(){        mHourPaint = new Paint();        mHourPaint.setAntiAlias(true);        mHourPaint.setStyle(Paint.Style.FILL);        mHourPaint.setStrokeWidth(16);        mHourPaint.setColor(mHourPointColor);        mMinutePaint = new Paint();        mMinutePaint.set(mHourPaint);        mMinutePaint.setStrokeWidth(12);        mMinutePaint.setColor(mMinutePointColor);        mSecondPaint = new Paint();        mSecondPaint.set(mHourPaint);        mSecondPaint.setStrokeWidth(7);        mSecondPaint.setColor(mSecondPointColor);        mEndPointLength = mWatchRadius/6; //(修飾部分)指標尾部長度,定義為錶盤半徑的六分之一    }</span>
畫指標

<span style="font-size:14px;">/**     * 畫指標     * @param canvas     */    private void paintPoint(Canvas canvas){        initPointPaint();        Calendar c = Calendar.getInstance(); //取目前時間        int hour = c.get(Calendar.HOUR_OF_DAY);        int minute = c.get(Calendar.MINUTE);        int second = c.get(Calendar.SECOND);        //繪製時針        canvas.save();        canvas.rotate(hour*30);        canvas.drawLine(0,0,0,-mHourPointLength,mHourPaint);        canvas.drawLine(0,0,0,mEndPointLength,mHourPaint);        canvas.restore();        //繪製分針        canvas.save();        canvas.rotate(minute*6);        canvas.drawLine(0,0,0,-mMinutePointLength,mMinutePaint);        canvas.drawLine(0,0,0,mEndPointLength,mMinutePaint);        canvas.restore();        //繪製秒針        canvas.save();        canvas.rotate(second*6);        canvas.drawLine(0,0,0,-mSecondPointLength,mSecondPaint);        canvas.drawLine(0,0,0,mEndPointLength,mSecondPaint);        canvas.restore();    }</span>
OK,該有的差不多都有了,直接在onDraw中調用吧

<span style="font-size:14px;">@Override    protected void onDraw(Canvas canvas) {        canvas.translate(getWidth()/2,getHeight()/2);        paintWatchBoard(canvas); //畫錶盤        paintScale(canvas); //畫刻度        paintPoint(canvas); //畫指標        canvas.drawCircle(0,0,15,mSecondPaint); //為了美觀,也讓錶盤更接近我們顯示生活中的樣子,我在圓盤中心畫了一個大紅圓點裝飾秒針        postInvalidateDelayed(1000); //每隔一秒鐘畫一次    }</span>
(⊙v⊙)嗯,自訂View大功告成,我們在布局檔案裡調用看下效果吧

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:zhusp="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@color/colorAccent">    <com.wondertek.propertyanimatordemo.WatchView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        zhusp:timeTextSize="20dp"        zhusp:watchRadius="150dp"        zhusp:hourPointLength="80dp"        zhusp:minutePointLength="100dp"        zhusp:secondPointLength="115dp"/></RelativeLayout></span>

最後我這裡的靜態效果是這樣的:

   

尾聲

寫完了,最後來加點逼格,學無止境,循序漸進。既然選擇了遠方,便只顧風雨兼程


參考資料:自訂View新手實戰-一步步實現精美的鐘錶介面


Android筆記自訂View之製作錶盤介面

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.