| 這是自定義View的第一篇文章,通過制作簡(jiǎn)單的自定義View來(lái)了解自定義View的流程。 自定義View是Android學(xué)習(xí)和開發(fā)中必不可少的一部分。通過自定義View我們可以制作豐富絢麗的控件,自定義View主要有三種方式,具體如下: 
 這里,我們講第三種方法來(lái)了解自定義View的流程。自定義View主要依賴的方法 自定義VIew中,我們主要重寫 
 下面我們先了解一下這兩個(gè)方法具體能做什么,然后我們通過一個(gè)實(shí)例來(lái)學(xué)習(xí)一下具體的用法。 onMeasureprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)我們從上面的方法可以看出 測(cè)量模式有一下三種: 
 具體的做法一般是,我們先根據(jù)參數(shù),得到具體的測(cè)量模式與測(cè)量值,在根據(jù)測(cè)試的模式不同,計(jì)算不同的寬度和高度。最后通過 onDraw
 上面說(shuō)了這么多,都是在YY,我們具體通過一個(gè)例子來(lái)走一遍自定義View的流程。效果如下: 首先我們新建一個(gè)CircleLoadingView.java文件。該類繼承View,生成構(gòu)造器,顯式調(diào)用父類的構(gòu)造器,并初始化我們的Paint對(duì)象,覆寫onMeasure,onDraw方法,實(shí)現(xiàn)自定義View.第一步——初始化 在構(gòu)造方法中,我們調(diào)用自己寫的initView方法來(lái)初始化Paint對(duì)象 private void initView{        paint = new Paint;        //設(shè)置畫筆的顏色        paint.setColor(circleColor);        //設(shè)置抗鋸齒,讓圖像更清晰        paint.setAntiAlias(true);        //設(shè)置畫筆的風(fēng)格,有三種屬性FILL,STROLE,FILL_AND_STROKE,我們不需要填充,所以設(shè)置為STROKE        paint.setStyle(Paint.Style.STROKE);        //設(shè)置畫筆的粗細(xì)        paint.setStrokeWidth(circleStrokewidth);    }onMeasure接下來(lái),我們需要測(cè)量我們的View的大小,重寫 @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //設(shè)置一個(gè)默認(rèn)的寬和高,AT_MOST模式需要        int result = 0;        //通過MeasureSpec.getMode與getSize方法獲取寬高的測(cè)量方式與測(cè)量大小        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        //保存最后的測(cè)量值,優(yōu)化代碼的話可以不用這個(gè)變量的。        int width = 0,height = 0;        //對(duì)測(cè)量模式進(jìn)行判斷,如果是EXACTLY的話則最后的測(cè)量值就是系統(tǒng)幫我們測(cè)量的結(jié)果。        if (widthMode == MeasureSpec.EXACTLY) { width = widthSize;        }else{ //如果是UNSPECIFIED 則使用我們的默認(rèn)值作為最后的測(cè)量值 result = 300; //如果是AT_MOST 則就要用系統(tǒng)測(cè)量結(jié)果與我們默認(rèn)結(jié)果取最小值來(lái)決定最后的測(cè)量結(jié)果 if (widthMode == MeasureSpec.AT_MOST) { width = Math.min(result,widthSize); }        }        //高度和寬度的過程是一致的。        if (heightMode == MeasureSpec.EXACTLY) { height = heightSize;        }else { result = 300; if (heightMode == MeasureSpec.AT_MOST) { height = Math.min(result, heightSize); }        }        //把我們最后的寬和高設(shè)置進(jìn)去        setMeasuredDimension(width,height);    }這就是 onDraw我們基本已經(jīng)完成了80%的工作了,接下來(lái)只需要重寫 @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //決定我們的弧形外接的矩形的寬和高        float wdistance = (float)(wlength * 0.6);        float hdistance = (float)(hlength * 0.6);        //定義外接矩形        RectF rectF = new RectF( wlength / 2 - wdistance / 2, hlength / 2 - hdistance / 2, wlength / 2 + wdistance / 2, hlength / 2 + hdistance / 2);         //畫弧形        canvas.drawArc( rectF,//外接矩形 270,//起始角度 (float)(240),//劃過的度數(shù) false,//是否是扇形 paint//畫筆        );    }看了上面的代碼,可能有些糊涂,因?yàn)槔锩娑嗔撕芏鄾]有提到的變量。首先的變量就是  wlength = width; hlength = height;同時(shí)我們定義了外接矩形的寬和高就是我們View的0.6倍,上,下, 左,右各留了0.2倍的內(nèi)邊距。然后通過new Rectf方法來(lái)生成矩形對(duì)象,4個(gè)參數(shù)分別為矩形的左邊距Y軸的距離(也就是說(shuō)X軸的坐標(biāo)),上邊距X軸的距離(也就是說(shuō)Y軸的坐標(biāo)),右邊距Y軸的距離(也就是說(shuō)X軸的坐標(biāo)),下邊距Y軸的距離(也就是說(shuō)Y軸的坐標(biāo))。具體見下圖 canvas 實(shí)際上就是這個(gè)坐標(biāo)軸。 定義好外接矩形之后,我們開始調(diào)用drawArc方法開始繪制弧形,這個(gè)方法接受5個(gè)參數(shù),第二個(gè)參數(shù)是弧起始的角度,這個(gè)接受一個(gè)整數(shù)代表角度,他是這樣確定起始的角度的。以我們的手表的3點(diǎn)開始,順時(shí)針轉(zhuǎn)過我們定義的角度,這時(shí)的位置就是我們開始的位置,比如我們現(xiàn)在定義的是270,那就是手表3點(diǎn)的位置轉(zhuǎn)過270度為我們弧形開始的位置。就是12點(diǎn)的位置。然后第三個(gè)參數(shù),代表弧形劃過的角度。也是順時(shí)針。第四個(gè)參數(shù)則代表是否用扇形,我們這里不用,也就是說(shuō)只是一個(gè)兩個(gè)端點(diǎn)不連接圓心的弧,第五個(gè)是我們初始化過的paint。這樣我們的自定義的弧形就出來(lái)了。 我們就可以把我們的控件放到xml中,當(dāng)成普通的view去引用了。直接看代碼: 這個(gè)弧形其實(shí)并沒有卵用,不能動(dòng)。我們接下來(lái)讓他動(dòng)起來(lái),這里我們就用繪圖自帶的方法 那這次我們只需要在onDraw方法中,不斷修改弧形的第二個(gè)參數(shù),讓他每次不同就可以了。具體的我們看代碼: @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        float wdistance = (float)(wlength * 0.6);        float hdistance = (float)(hlength * 0.6);        RectF rectF = new RectF( wlength / 2 - wdistance / 2, hlength / 2 - hdistance / 2, wlength / 2 + wdistance / 2, hlength / 2 + hdistance / 2);        canvas.drawArc( rectF, //每次重繪,起始的角度就會(huì)多5度。 270 + 5 * i, (float)(240), false, paint        );        i++;        //調(diào)用重繪,來(lái)實(shí)現(xiàn)圖像不斷繪制        postInvalidate;    }這樣,我們?cè)俅芜\(yùn)行程序的時(shí)候,我們的弧形就動(dòng)起來(lái)。當(dāng)我們?cè)诮佑|動(dòng)畫概念的時(shí)候,又會(huì)發(fā)現(xiàn)有很多方法實(shí)現(xiàn)弧形旋轉(zhuǎn)。第五步——完善 前面4步,我們已經(jīng)實(shí)現(xiàn)了簡(jiǎn)單的自定義View,并且有一個(gè)可觀的效果。但是我們還要完善一下,比如我們可以在XML中指定弧形的顏色,弧形的粗細(xì)。這個(gè)時(shí)候,我們就需要在values文件下新建一個(gè)attrs.xml。在里面制定我們的自定義屬性,然后在我們的View文件中讀取這些屬性。 我們先看一下attrs.xml中,我們的代碼: 這里,我們就定義了2個(gè)屬性,一個(gè)是弧形的顏色,一個(gè)是弧形的粗細(xì),格式分別是color和float。然后我們?cè)趘iew中的initView代碼中,獲取那些屬性。代碼如下: TypedArray ta = getContext.obtainStyledAttributes(attrs, R.styleable.CircleLoadingView);        circleStrokewidth = ta.getFloat(R.styleable.CircleLoadingView_circleStrokewidth, 0);        circleColor = ta.getColor(R.styleable.CircleLoadingView_circleColor, 0);然后我們就可以在我們的xml中引用這些屬性了。 這里的circleview是要在根布局的設(shè)置中聲明的  因?yàn)?,這個(gè)主要出現(xiàn)在加載過程中,所以他需要一個(gè)方法來(lái)讓他顯示和隱藏。我們?cè)赩iew的文件中,設(shè)置一個(gè)方法叫做 當(dāng)為true的時(shí)候,就可以顯示,當(dāng)為false就可以隱藏。這樣,這個(gè)自定義View就比較完善了。 隱藏方法代碼如下: public void setViewVisable(boolean choose) {        if (choose) { this.setVisibility(View.VISIBLE);        }else{ this.setVisibility(View.GONE);        }    }這個(gè)小控件的源碼我放到網(wǎng)上了,大家可以對(duì)照參考下 | 
|  | 
來(lái)自: 月冷星河 > 《Android文章》