日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

通過(guò)圓形載入View了解自定義View

 月冷星河 2016-07-22

這是自定義View的第一篇文章,通過(guò)制作簡(jiǎn)單的自定義View來(lái)了解自定義View的流程。 自定義View是Android學(xué)習(xí)和開(kāi)發(fā)中必不可少的一部分。通過(guò)自定義View我們可以制作豐富絢麗的控件,自定義View主要有三種方式,具體如下:

  1. 繼承已有的View,來(lái)擴(kuò)展我們的View
  2. 組合多個(gè)View來(lái)實(shí)現(xiàn)一個(gè)復(fù)合的View
  3. 完全重寫(xiě)View,來(lái)實(shí)現(xiàn)制作全新的控件

這里,我們講第三種方法來(lái)了解自定義View的流程。

自定義View主要依賴的方法

自定義VIew中,我們主要重寫(xiě)onMeasure,onDraw這兩種方法來(lái)展現(xiàn)一個(gè)View。

onMeasure:主要工作是對(duì)我們要繪制的View進(jìn)行測(cè)量,因?yàn)椴贿M(jìn)行測(cè)量的話,系統(tǒng)不知道要繪制的View有多大,無(wú)法繪制出我們需要的樣子。

onDraw: 主要工作就是繪制我們需要的圖形,這個(gè)是自定義View中定制性最強(qiáng)也是最主要的工作。

下面我們先了解一下這兩個(gè)方法具體能做什么,然后我們通過(guò)一個(gè)實(shí)例來(lái)學(xué)習(xí)一下具體的用法。

onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

我們從上面的方法可以看出onMeasure方法中有兩個(gè)參數(shù)widthMeasureSpec,heightMeasureSpec這兩個(gè)參數(shù)每一個(gè)參數(shù)中都包含了測(cè)量值的大小和測(cè)量的模式。

測(cè)量模式有一下三種:

  1. EXACTLY
    當(dāng)我們把控layout_width或者layout_height屬性設(shè)為match_parent或者是個(gè)100dp那樣的精確值時(shí)就會(huì)用這種測(cè)量模式。
  2. AT_MOST
    即最大值模式,當(dāng)控件的layout_width屬性或者layout_height指定為wrap_content時(shí),空間大小一般隨著控件的子控件或者內(nèi)容的變化而變化,這是控件的尺寸只要不超過(guò)父控件允許的最大尺寸就行了。
  3. UNSPECIFIED
    這個(gè)是我們按照自身的想法,想繪制多大就繪制多大,沒(méi)有任何限制。

具體的做法一般是,我們先根據(jù)參數(shù),得到具體的測(cè)量模式與測(cè)量值,在根據(jù)測(cè)試的模式不同,計(jì)算不同的寬度和高度。最后通過(guò)setMeasuredDimension(int measuredWidth,int measuredHeight)將我們計(jì)算過(guò)的寬和高設(shè)置進(jìn)去,完成測(cè)量工作。

onDraw

onDraw(Canvas canvas)是我們展現(xiàn)自定義View的主要方法,他的參數(shù)是一個(gè)canvas也就是說(shuō)一個(gè)畫(huà)布,為了繪制圖案,我們有了畫(huà)布以外,我們還需要一個(gè)畫(huà)筆Paint。這個(gè)畫(huà)筆來(lái)決定你畫(huà)圖案的顏色,線條的粗細(xì),是否抗鋸齒,圖案的風(fēng)格等等。而畫(huà)什么圖案就交由canvas對(duì)象,調(diào)用canvas.drawXXX來(lái)實(shí)現(xiàn)想要的圖案,具體的文檔,參見(jiàn)Canvas官方文檔

自制圓形載入View

上面說(shuō)了這么多,都是在YY,我們具體通過(guò)一個(gè)例子來(lái)走一遍自定義View的流程。效果如下:

通過(guò)圓形載入View了解自定義View

首先我們新建一個(gè)CircleLoadingView.java文件。該類繼承View,生成構(gòu)造器,顯式調(diào)用父類的構(gòu)造器,并初始化我們的Paint對(duì)象,覆寫(xiě)onMeasure,onDraw方法,實(shí)現(xiàn)自定義View.

第一步——初始化

在構(gòu)造方法中,我們調(diào)用自己寫(xiě)的initView方法來(lái)初始化Paint對(duì)象

private void initView{ paint = new Paint; //設(shè)置畫(huà)筆的顏色 paint.setColor(circleColor); //設(shè)置抗鋸齒,讓圖像更清晰 paint.setAntiAlias(true); //設(shè)置畫(huà)筆的風(fēng)格,有三種屬性FILL,STROLE,FILL_AND_STROKE,我們不需要填充,所以設(shè)置為STROKE paint.setStyle(Paint.Style.STROKE); //設(shè)置畫(huà)筆的粗細(xì) paint.setStrokeWidth(circleStrokewidth); }
第二步——onMeasure

接下來(lái),我們需要測(cè)量我們的View的大小,重寫(xiě)onMeasure方法

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //設(shè)置一個(gè)默認(rèn)的寬和高,AT_MOST模式需要 int result = 0; //通過(guò)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); } } //高度和寬度的過(guò)程是一致的。 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); }

這就是onMeasure方法的代碼,可以看出來(lái),這個(gè)都是可以放到其他地方復(fù)用的模板代碼。

第三步——onDraw

我們基本已經(jīng)完成了80%的工作了,接下來(lái)只需要重寫(xiě)onDraw繪制我們需要的一個(gè)弧形就可以了。

@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); //畫(huà)弧形 canvas.drawArc( rectF,//外接矩形 270,//起始角度 (float)(240),//劃過(guò)的度數(shù) false,//是否是扇形 paint//畫(huà)筆 ); }

看了上面的代碼,可能有些糊涂,因?yàn)槔锩娑嗔撕芏鄾](méi)有提到的變量。首先的變量就是wlength,與hlength這個(gè)指的是我們onMeasure測(cè)量以后的寬和高,我們保存下來(lái)。在onMeasure方法中,我們加入下面代碼。

wlength = width; hlength = height;

同時(shí)我們定義了外接矩形的寬和高就是我們View的0.6倍,上,下, 左,右各留了0.2倍的內(nèi)邊距。然后通過(guò)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))。具體見(jiàn)下圖

通過(guò)圓形載入View了解自定義View

canvas 實(shí)際上就是這個(gè)坐標(biāo)軸。

定義好外接矩形之后,我們開(kāi)始調(diào)用drawArc方法開(kāi)始繪制弧形,這個(gè)方法接受5個(gè)參數(shù),第二個(gè)參數(shù)是弧起始的角度,這個(gè)接受一個(gè)整數(shù)代表角度,他是這樣確定起始的角度的。以我們的手表的3點(diǎn)開(kāi)始,順時(shí)針轉(zhuǎn)過(guò)我們定義的角度,這時(shí)的位置就是我們開(kāi)始的位置,比如我們現(xiàn)在定義的是270,那就是手表3點(diǎn)的位置轉(zhuǎn)過(guò)270度為我們弧形開(kāi)始的位置。就是12點(diǎn)的位置。然后第三個(gè)參數(shù),代表弧形劃過(guò)的角度。也是順時(shí)針。第四個(gè)參數(shù)則代表是否用扇形,我們這里不用,也就是說(shuō)只是一個(gè)兩個(gè)端點(diǎn)不連接圓心的弧,第五個(gè)是我們初始化過(guò)的paint。這樣我們的自定義的弧形就出來(lái)了。

我們就可以把我們的控件放到xml中,當(dāng)成普通的view去引用了。直接看代碼:

這里的引用View一定要用全名。我們就可以直接運(yùn)行程序。
第四步——?jiǎng)悠饋?lái)

這個(gè)弧形其實(shí)并沒(méi)有卵用,不能動(dòng)。我們接下來(lái)讓他動(dòng)起來(lái),這里我們就用繪圖自帶的方法postInvalidate來(lái)實(shí)現(xiàn)重繪。要讓一個(gè)圖像動(dòng)起來(lái)最簡(jiǎn)單的辦法就是讓他在每一個(gè)坐標(biāo)點(diǎn)就繪制一下,然后讓他在每個(gè)坐標(biāo)點(diǎn)都出現(xiàn)一次就實(shí)現(xiàn)了動(dòng)畫(huà)的效果。就像小時(shí)候有那種很多頁(yè)的漫畫(huà)書(shū),我們快速翻閱漫畫(huà)書(shū)就感覺(jué)漫畫(huà)書(shū)中的漫畫(huà)動(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)畫(huà)概念的時(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è)置中聲明的 xmlns:circleview='http://schemas./apk/res-auto'

因?yàn)?,這個(gè)主要出現(xiàn)在加載過(guò)程中,所以他需要一個(gè)方法來(lái)讓他顯示和隱藏。我們?cè)赩iew的文件中,設(shè)置一個(gè)方法叫做setViewVisable

當(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); } }
PS

這個(gè)小控件的源碼我放到網(wǎng)上了,大家可以對(duì)照參考下

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多