1. 程式人生 > >手把手帶你畫一個 時尚儀表盤 Android 自己定義View

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

androi alias 屬性 extend 三角函數 blank xutils content 還在


拿到美工效果圖。咱們程序猿就得畫得一模一樣。

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

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


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

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


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

技術分享

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

上一個動態圖:

技術分享

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

技術分享


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

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

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);

畫出來是這種效果。

技術分享

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

技術分享

由於大圓和裏面粗弧的長短不一致,這裏使用百分比來計算 所以會造成指針偏差,那麽這裏把 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