手把手帶你畫一個 時尚儀錶盤 Android 自己定義View

來源:互聯網
上載者:User

標籤:1.0   注意   als   引入   分享   his   etc   else   panel   


拿到美工。咱們程式猿就得畫得一模一樣。

為了不被老闆噴,僅僅能多練啊。

聽說你認為前面幾篇都so easy,那今天就帶你做個相對照較複雜的。


轉載請註明出處:http://blog.csdn.net/wingichoy/article/details/50468674

注意:每一篇部落格都是建立在之前部落格的基礎知識上的,假設你剛接觸自己定義view。能夠來說說自己定義view簡單學習的方式這裡看我曾經的文章。記錄了我學習自己定義view的過程,並且前幾篇部落格或多或少犯了一些錯誤(反覆繪製,onDraw裡new對象等等)。這裡我並不想改正博文中的錯誤。由於些錯誤是大家常常會犯的,後來的部落格都有指出這些錯誤,以及不再犯。這是一個學習的過程。所以我想把錯誤的經曆記錄下來。等成為高手 回頭看看當年的自己是多麼菜。。也會有成就感。


今天的例如以下(左邊是ui圖 右邊是實現圖):

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

自我感覺整體效果還不錯。至少大概畫得一樣了。

上一個動態圖:


事實上這個效果實現起來也不是非常難,就是計算座標,弧度之類的可能會比較麻煩,這裡分享寫這個當中一張手稿。請無視掉非常醜的字。事實上做自己定義view 還是要在紙上多畫。所以希望大家也能這麼畫畫,思路會非常順。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >


好的了,廢話不多說。快開始。

首先自己定義屬性  建構函式,測量什麼的 你肯定已經非常熟練 直接貼代碼了,凝視寫的非常清楚

public class PanelView extends View {    private int mWidth;    private int mHeight;    private int mPercent;    //刻度寬度    private float mTikeWidth;    //第二個弧的寬度    private int mScendArcWidth;    //最小圓的半徑    private int mMinCircleRadius;    //文字矩形的寬    private int mRectWidth;    //文字矩形的高    private int mRectHeight;    //文字內容    private String mText = "";    //文字的大小    private int mTextSize;    //設定文字顏色    private int mTextColor;    private int mArcColor;    //小圓和指標顏色    private int mMinCircleColor;    //刻度的個數    private int mTikeCount;    private Context mContext;    public PanelView(Context context) {        this(context, null);    }    public PanelView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public PanelView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.PanelView,defStyleAttr,0);        mArcColor = a.getColor(R.styleable.PanelView_arcColor, Color.parseColor("#5FB1ED"));        mMinCircleColor = a.getColor(R.styleable.PanelView_pointerColor,Color.parseColor("#C9DEEE"));        mTikeCount = a.getInt(R.styleable.PanelView_tikeCount,12);        mTextSize = a.getDimensionPixelSize(PxUtils.spToPx(R.styleable.PanelView_android_textSize,mContext),24);        mText = a.getString(R.styleable.PanelView_android_text);        mScendArcWidth = 50;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        if (widthMode == MeasureSpec.EXACTLY) {            mWidth = widthSize;        }else {            mWidth = PxUtils.dpToPx(200,mContext);        }        if (heightMode == MeasureSpec.EXACTLY) {            mHeight = heightSize;        }else {            mHeight = PxUtils.dpToPx(200,mContext);        }        Log.e("wing",mWidth+"");        setMeasuredDimension(mWidth, mHeight);    }
自己定義屬性attr.xml

<?xml version="1.0" encoding="utf-8"?

><resources> <declare-styleable name="PanelView"> <attr name="arcColor" format="color"/> <attr name="arcWidth" format="dimension"/> <attr name="android:text"/> <attr name="tikeCount" format="integer"/> <attr name="pointerColor" format="color"/> <attr name="android:textSize"/> </declare-styleable></resources>




之後來重頭戲,也就是繪製。就像畫畫一樣,再複雜的view也是一筆一筆畫出來的。所以我們把這個view分解。

大概分解成例如以下:1.最外面的弧   2.裡面的粗弧   3.中間小圓   4.最小的圓  5.刻度   6.指標  7.矩形  8.文字

相信讓你分開畫一定難不倒你。那組合在一起 就是這個view啦。以下開始我們的ondraw()


依照這個分解來:

1.繪製最外面的弧   這裡須要注意的一點是。假設想讓這個圓在view裡 記得減去畫筆寬度的一半  由於半徑是從圓心到畫筆寬度的中間算的,所以這裡畫弧的矩形是  new RectF(strokeWidth, strokeWidth, mWidth - strokeWidth, mHeight - strokeWidth)

     Paint p = new Paint();         int strokeWidth = 3;        p.setStrokeWidth(strokeWidth);        p.setAntiAlias(true);        p.setStyle(Paint.Style.STROKE);        p.setColor(mArcColor);        //最外麵線條        canvas.drawArc(new RectF(strokeWidth, strokeWidth, mWidth - strokeWidth, mHeight - strokeWidth), 145, 250, false, p);

畫出來是這種效果。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

2.繪製裡面的粗弧,這裡比較麻煩的就是須要分為四段,看圖:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

由於大圓和裡面粗弧的長短不一致,這裡使用百分比來計算 所以會造成指標偏差,那麼這裡把 1、2兩個部分固定來畫。然後是3 充滿的部分。用百分比來計算須要畫多少度,最後是4 空白的部分。

首先把粗弧的矩形畫出來。這裡固定了比大弧半徑少50(這裡事實上能夠改進,你能夠改成動態讓他更靈活),然後計算出百分比。

RectF secondRectF = new RectF(strokeWidth + 50, strokeWidth + 50, mWidth - strokeWidth - 50, mHeight - strokeWidth - 50);        float secondRectWidth = mWidth - strokeWidth - 50 - (strokeWidth + 50);        float secondRectHeight = mHeight - strokeWidth - 50 - (strokeWidth + 50);        float percent = mPercent / 100f;

接下來繪製1弧。先算出fill充滿部分的度數,由於是突出的,所以假設百分比為0,突出左端為白色 假設不為零,則和充滿顏色統一。

        //充滿的圓弧的度數    -5是大小弧的偏差        float fill = 250 * percent ;        //空的圓弧的度數        float empty = 250 - fill;//        Log.e("wing", fill + "");        if(percent==0){            p.setColor(Color.WHITE);        }        //畫粗弧突出部分左端        canvas.drawArc(secondRectF,135,11,false,p);

然後繪製2弧 也就是fill充滿的弧,

canvas.drawArc(secondRectF, 145, fill, false, p);

接下來是3弧。也就是empty未充滿的弧。是白色的

 p.setColor(Color.WHITE);        //畫弧胡的未充滿部分        canvas.drawArc(secondRectF, 145 + fill, empty, false, p);

最後。畫出右邊突出的4弧, 假設百分比為100 那麼和充滿的顏色一致,否則為白色

 //畫粗弧突出部分右端        if(percent == 1){            p.setColor(mArcColor);        }        canvas.drawArc(secondRectF,144+fill+empty,10,false,p);

這樣粗弧也就畫完了 來看看效果,就畫了兩條弧線(實際是5條),就成型了。



3.中間的小圓外圈。他的圓心不用多說 是整個view的中心

        p.setColor(mArcColor);        //繪製小圓外圈        p.setStrokeWidth(3);        canvas.drawCircle(mWidth / 2, mHeight / 2, 30, p);

4.繪製內圓,圓心一樣的。半徑和畫筆粗度改變一下

        //繪製小圓內圈        p.setColor(mMinCircleColor);        p.setStrokeWidth(8);        mMinCircleRadius = 15;        canvas.drawCircle(mWidth / 2, mHeight / 2, mMinCircleRadius, p);


5.刻度  刻度處理起來可能比較麻煩,用三角函數算座標啊 迴圈畫出來。

這裡提供一種比較簡單的方法:旋轉畫布。

首先引入一個概念,什麼叫旋轉畫布呢,就是把你的畫布旋轉。。經過測試,旋轉以後,整個座標軸都會相應旋轉。一張圖舉例說明下。


大概就是這個意思。畫布旋轉之後 座標系也就旋轉了,可是原來的映像還在,所以說你比方這個點 x,y旋轉前在這個位置。 那麼旋轉後就是另外一個位置了。可是他們的座標是同樣的。 所以刻度也能夠考這樣的方法畫。我們僅僅要畫出最頂端的刻度 然後旋轉就能夠了。


繪製第一段刻度。 然後總共是250的弧度  計算出每一個刻度的度數     用250除以刻度數mTikeCount,就是每次旋轉的度數。接下來把畫布逐步旋轉,依照原座標繪製,就可以繪製出右半部分刻度。  注意:為了讓之後的繪製正常,務必把畫布轉回原來的位置

        //繪製刻度。        p.setColor(mArcColor);        //繪製第一條最上面的刻度        mTikeWidth = 20;        p.setStrokeWidth(3);        canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);        //旋轉的角度        float rAngle = 250f / mTikeCount;        //通過旋轉畫布 繪製右面的刻度        for (int i = 0; i < mTikeCount / 2; i++) {            canvas.rotate(rAngle, mWidth / 2, mHeight / 2);            canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);        }        //如今須要將將畫布旋轉回來        canvas.rotate(-rAngle * mTikeCount / 2, mWidth / 2, mHeight / 2);


左半部分同理,須要改變的度數為負 就好了

        //通過旋轉畫布 繪製左面的刻度        for (int i = 0; i < mTikeCount / 2; i++) {            canvas.rotate(-rAngle, mWidth / 2, mHeight / 2);            canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);        }        //如今須要將將畫布旋轉回來        canvas.rotate(rAngle * mTikeCount / 2, mWidth / 2, mHeight / 2);


6.指標   指標的繪製和刻度相似,先算出來百分比所佔的度數 然後依據 是否大於50%來旋轉畫布。

指標的起終點是 總view高度的一半 粗弧矩形的一半 加上小圓。前面座標解說了那麼。這個也一樣。自己拿起筆算一算。


注意這裡畫布旋轉我通過計算得出一個公式 250 * percent - 250/2。

假設小於50% 則為負   假設大於50%則為正。然後進行旋轉。

切忌最後一定要將畫布轉回來。

        //繪製指標        p.setColor(mMinCircleColor);        p.setStrokeWidth(4);        //依照百分比繪製刻度        canvas.rotate(( 250 * percent - 250/2), mWidth / 2, mHeight / 2);        canvas.drawLine(mWidth / 2, (mHeight / 2 - secondRectHeight / 2) + mScendArcWidth / 2 + 2, mWidth / 2, mHeight / 2 - mMinCircleRadius, p);        //將畫布旋轉回來        canvas.rotate(-( 250 * percent - 250/2), mWidth / 2, mHeight / 2);


接下來就是畫矩形和文字。沒什麼好說的了,座標也是X周圍mWidth/2   y軸自己依據圓心微調一個距離

    //繪製矩形        p.setStyle(Paint.Style.FILL);        p.setColor(mArcColor);        mRectWidth = 60;        mRectHeight = 25;        //文字矩形的最底部座標        float rectBottomY = mHeight/2 + secondRectHeight/3+mRectHeight;        canvas.drawRect(mWidth/2-mRectWidth/2,mHeight/2 + secondRectHeight/3,mWidth/2+mRectWidth/2,rectBottomY,p);        p.setTextSize(mTextSize);        mTextColor = Color.WHITE;        p.setColor(mTextColor);        float txtLength = p.measureText(mText);        canvas.drawText(mText,(mWidth-txtLength)/2,rectBottomY + 40,p);        super.onDraw(canvas);


這樣完畢了整個view的繪製。


以下要做的就是為了方便使用者。提供一些設定屬性的方法。

 /**     * 設定百分比     * @param percent     */    public void setPercent(int percent) {        mPercent = percent;        invalidate();    }    /**     * 設定文字     * @param text     */    public void setText(String text){        mText = text;        invalidate();    }    /**     * 設定圓弧顏色     * @param color     */    public void setArcColor(int color){        mArcColor = color;        invalidate();    }    /**     * 設定指標顏色     * @param color     */    public void setPointerColor(int color){        mMinCircleColor = color;        invalidate();    }    /**     * 設定文字大小     * @param size     */    public void setTextSize(int size){        mTextSize = size;        invalidate();    }    /**     * 設定粗弧的寬度     * @param width     */    public void setArcWidth(int width){        mScendArcWidth = width;        invalidate();    }


大功告成!

。一個看似複雜的view  經過我們一步一步繪製遍完畢了。

事實上技術的養成也是這樣。僅僅要一步一步腳踏實地的去練習。我相信總有一天我能成為大神。


本項目地址 :PanelView   求關注  求評論  求star!!。!。!

手把手帶你畫一個 時尚儀錶盤 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.