中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

Android中怎么自定義Viewgroup

這篇文章給大家介紹Android 中怎么自定義Viewgroup,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

成都創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比東豐網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式東豐網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋東豐地區(qū)。費(fèi)用合理售后完善,10多年實(shí)體公司更值得信賴。

viewgroup 的測(cè)量布局流程基本梳理

稍微回顧下,基本的viewgroup繪制和布局流程中的重點(diǎn):

  1. view  在onMeasure()方法中進(jìn)行自我測(cè)量和保存,也就是說(shuō)對(duì)于view(不是viewgroup噢)來(lái)說(shuō)一定在onMeasure方法中計(jì)算出自己的尺寸并且保存下來(lái)

  2. viewgroup實(shí)際上最終也是循環(huán)從上大小來(lái)調(diào)用子view的measure方法,注意子view的measure其實(shí)最終調(diào)用的是子view的onMeasure  方法。所以我們理解這個(gè)過程為:  viewgroup循環(huán)遍歷調(diào)用所有子view的onmeasure方法,利用onmeasure方法計(jì)算出來(lái)的大小,來(lái)確定這些子view最終可以占用的大小和所處的布局的位置。

  3. measure方法是一個(gè)final方法,可以理解為做測(cè)量工作準(zhǔn)備工作的,既然是final方法所以我們無(wú)法重寫它,不需要過多關(guān)注他,因?yàn)閙easure最終要調(diào)用onmeasure  ,這個(gè)onmeasure我們是可以重寫的。要關(guān)注這個(gè)。layout和onlayout是一樣的關(guān)系。

  4. 父view調(diào)用子view的layout方法的時(shí)候會(huì)把之前measure階段確定的位置和大小都傳遞給子view。

  5. 對(duì)于自定義view/viewgroup來(lái)說(shuō) 我們幾乎只需要關(guān)注下面三種需求:

  • 對(duì)于已有的android自帶的view,我們只需要重寫他的onMeasure方法即可。修改一下這個(gè)尺寸即可完成需求。

  • 對(duì)于android系統(tǒng)沒有的,屬于我們自定義的view,比上面那個(gè)要復(fù)雜一點(diǎn),要完全重寫onMeasure方法。

  • 第三種最復(fù)雜,需要重寫onmeasure和onlayout2個(gè)方法,來(lái)完成一個(gè)復(fù)雜viewgroup的測(cè)量和布局。

onMeasure方法的特殊說(shuō)明:

Android 中怎么自定義Viewgroup

如何理解父view對(duì)子view的限制?

onMeasure的兩個(gè)參數(shù)既然是父view對(duì)子view的限制,那么這個(gè)限制的值到底是哪來(lái)的呢?

實(shí)際上,父view對(duì)子view的限制絕大多數(shù)就來(lái)自于我們開發(fā)者所設(shè)置的layout開頭的這些屬性

比方說(shuō)我們給一個(gè)imageview設(shè)置了他的layout_width和layout_height  這2個(gè)屬性,那這2個(gè)屬性其實(shí)就是我們開發(fā)者所期望的寬高屬性,但是要注意了,  設(shè)置的這2個(gè)屬性是給父view看的,實(shí)際上對(duì)于絕大多數(shù)的layout開頭的屬性這些屬性都是設(shè)置給父view看的

為什么要給父view看?因?yàn)楦竩iew要知道這些屬性以后才知道要對(duì)子view的測(cè)量加以什么限制?

到底是不限制(UNSPECIFIED)?還是限制個(gè)***值(AT_MOST),讓子view不超過這個(gè)值?還是直接限制死,我讓你是多少就得是多少(EXACTLY)。

自定義一個(gè)BannerImageView 修改onMeasure方法

所謂bannerImageview,就是很多電商其實(shí)都會(huì)放廣告圖,這個(gè)廣告圖的寬高比都是可變的,我們?cè)谌粘i_發(fā)過程中也會(huì)經(jīng)常接觸到這種需求:imageview的寬高比  在高保真中都標(biāo)注出來(lái),但是考慮到很多手機(jī)的屏幕寬度或者高度都不確定所以我們通常都要手動(dòng)來(lái)計(jì)算出這個(gè)imageview高度或者寬度,然后動(dòng)態(tài)改變width或者h(yuǎn)eight的值。這種方法可用但是很麻煩這里給出一個(gè)自定義的imageview,通過設(shè)置一個(gè)ratio的屬性即可動(dòng)態(tài)的設(shè)置iv的高度。很是方便

Android 中怎么自定義Viewgroup

看下效果

Android 中怎么自定義Viewgroup

***看下代碼,重要的部分都寫在注釋里了,不再過多講了。

public class BannerImageView extends ImageView {      //寬高比     float ratio;      public BannerImageView(Context context) {         super(context);     }      public BannerImageView(Context context, AttributeSet attrs) {         super(context, attrs);          TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BannerImageView);         ratio = typedArray.getFloat(R.styleable.BannerImageView_ratio, 1.0f);         typedArray.recycle();     }      public BannerImageView(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }      @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         //人家自己的測(cè)量還是要自己走一遍的,因?yàn)檫@個(gè)方法內(nèi)部會(huì)調(diào)用setMeasuredDimension方法來(lái)保存測(cè)量結(jié)果了         //只有保存了以后 我們才能取得這個(gè)測(cè)量結(jié)果 否則你下面是取不到的         super.onMeasure(widthMeasureSpec, heightMeasureSpec);          //取測(cè)量結(jié)果         int mWidth = getMeasuredWidth();          int mHeight = (int) (mWidth * ratio);          //保存了以后,父view就可以拿到這個(gè)測(cè)量的寬高了。不保存是拿不到的噢。         setMeasuredDimension(mWidth, mHeight);     } }

自定義view,完全自己寫onMeasure方法

首先明確一個(gè)結(jié)論:

對(duì)于完全自定義的view,完全自己寫的onMeasure方法來(lái)說(shuō),你保存的寬高必須要符合父view的限制,否則會(huì)發(fā)生bug,保存父view對(duì)子view的限制的方法也很簡(jiǎn)單直接調(diào)用resolveSize方法即可。

Android 中怎么自定義Viewgroup
Android 中怎么自定義Viewgroup

所以對(duì)于完全自定義的view onMeasure方法也不難寫了,

  1. 先算自己想要的寬高,比如你畫了個(gè)圓,那么寬高就肯定是半徑的兩倍大小,  要是圓下面還有字,那么高度肯定除了半徑的兩倍還要有字體的大小。對(duì)吧。很簡(jiǎn)單。這個(gè)純看你自定義view是啥樣的

  2. 算完自己想要的寬高以后 直接拿resolveSize 方法處理一下 即可。

  3. ***setMeasuredDimension 保存。

范例:

public class LoadingView extends View {      //圓形的半徑     int radius;      //圓形外部矩形rect的起點(diǎn)     int left = 10, top = 30;       Paint mPaint = new Paint();      public LoadingView(Context context) {         super(context);     }      public LoadingView(Context context, AttributeSet attrs) {         super(context, attrs);         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);         radius = typedArray.getInt(R.styleable.LoadingView_radius, 0);     }      public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }      @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         super.onMeasure(widthMeasureSpec, heightMeasureSpec);           int width = left + radius * 2;         int height = top + radius * 2;          //一定要用resolveSize方法來(lái)格式化一下你的view寬高噢,否則遇到某些layout的時(shí)候一定會(huì)出現(xiàn)奇怪的bug的。         //因?yàn)椴挥眠@個(gè) 你就完全沒有父view的感受了 ***強(qiáng)調(diào)一遍         width = resolveSize(width, widthMeasureSpec);         height = resolveSize(height, heightMeasureSpec);          setMeasuredDimension(width, height);     }      @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);          RectF oval = new RectF(left, top,                 left + radius * 2, top + radius * 2);         mPaint.setColor(Color.BLUE);         canvas.drawRect(oval, mPaint);         //先畫圓弧         mPaint.setColor(Color.RED);         mPaint.setStyle(Paint.Style.STROKE);         mPaint.setStrokeWidth(2);         canvas.drawArc(oval, -90, 360, false, mPaint);     } }

布局文件:

<LinearLayout         android:layout_width="200dp"         android:layout_height="200dp"         android:background="#000000"         android:orientation="horizontal">          <com.example.a16040657.customviewtest.LoadingView             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:src="@mipmap/dly"             app:radius="200"></com.example.a16040657.customviewtest.LoadingView>          <com.example.a16040657.customviewtest.LoadingView             android:layout_marginLeft="10dp"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:src="@mipmap/dly"             app:radius="200"></com.example.a16040657.customviewtest.LoadingView>     </LinearLayout>

***效果:

Android 中怎么自定義Viewgroup

自定義一個(gè)viewgroup

這個(gè)其實(shí)也就是稍微復(fù)雜了一點(diǎn),但是還是有跡可循的,只是稍微需要一點(diǎn)額外的耐心。

自定義一個(gè)viewgroup 需要注意的點(diǎn)如下:

  1. 一定是先重寫onMeasure確定子view的寬高和自己的寬高以后 才可以繼續(xù)寫onlayout 對(duì)這些子view進(jìn)行布局噢~~

  2. viewgroup 的onMeasure其實(shí)就是遍歷自己的view 對(duì)自己的每一個(gè)子view進(jìn)行measure,絕大多數(shù)時(shí)候?qū)ψ觱iew的  measure都可以直接用  measureChild()這個(gè)方法來(lái)替代,簡(jiǎn)化我們的寫法,如果你的viewgroup很復(fù)雜的話無(wú)法就是自己寫一遍measureChild  而不是調(diào)用measureChild 罷了。

  3. 計(jì)算出viewgroup自己的尺寸并且保存,保存的方法還是哪個(gè)setMeasuredDimension 不要忘記了

  4. 逼不得已要重寫measureChild方法的時(shí)候,其實(shí)也不難無(wú)非就是對(duì)父view的測(cè)量和子view的測(cè)量  做一個(gè)取舍關(guān)系而已,你看懂了基礎(chǔ)的measureChild方法,以后就肯定會(huì)寫自己的復(fù)雜的measureChild方法了。

下面是一個(gè)極簡(jiǎn)的例子,一個(gè)很簡(jiǎn)單的flowlayout的實(shí)現(xiàn),沒有對(duì)margin  paddding做處理,也假設(shè)了每一個(gè)tag的高度是固定的,可以說(shuō)是極為簡(jiǎn)單了,但是麻雀雖小  五臟俱全,足夠你們好好理解自定義viewgroup的關(guān)鍵點(diǎn)了。

/**  * 寫一個(gè)簡(jiǎn)單的flowlayout 從左到右的簡(jiǎn)單layout,如果寬度不夠放 就直接另起一行l(wèi)ayout  * 這個(gè)類似的開源控件有很多,有很多寫的出色的,我這里只僅僅實(shí)現(xiàn)一個(gè)初級(jí)的flowlayout  * 也是最簡(jiǎn)單的,目的是為了理解自定義viewgroup的關(guān)鍵核心點(diǎn)。  * <p>  * 比方說(shuō)這里并沒有對(duì)padding或者margin做特殊處理,你們自己寫viewgroup的時(shí)候 記得把這些屬性的處理都加上  * 否則一旦有人用了這些屬性 發(fā)現(xiàn)沒有生效就比較難看了。。。。。。  */ public class SimpleFlowLayout extends ViewGroup {     public SimpleFlowLayout(Context context) {         super(context);     }      public SimpleFlowLayout(Context context, AttributeSet attrs) {         super(context, attrs);     }      public SimpleFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }      /**      * layout的算法 其實(shí)就是 不夠放剩下一行 那另外放一行 這個(gè)過程一定要自己寫一遍才能體會(huì),      * 個(gè)人有個(gè)人的寫法,說(shuō)不定你的寫法比開源的項(xiàng)目還要好      * 其實(shí)也沒什么夸張的,無(wú)法就是前面onMeasure結(jié)束以后 你可以拿到所有子view和自己的 測(cè)量寬高 然后就算唄      *      * @param changed      * @param l      * @param t      * @param r      * @param b      */      @Override     protected void onLayout(boolean changed, int l, int t, int r, int b) {         int childTop = 0;         int childLeft = 0;         int childRight = 0;         int childBottom = 0;          //已使用 width         int usedWidth = 0;           //customlayout 自己可使用的寬度         int layoutWidth = getMeasuredWidth();         Log.v("wuyue", "layoutWidth==" + layoutWidth);         for (int i = 0; i < getChildCount(); i++) {             View childView = getChildAt(i);             //取得這個(gè)子view要求的寬度和高度             int childWidth = childView.getMeasuredWidth();             int childHeight = childView.getMeasuredHeight();              //如果寬度不夠了 就另外啟動(dòng)一行             if (layoutWidth - usedWidth < childWidth) {                 childLeft = 0;                 usedWidth = 0;                 childTop += childHeight;                 childRight = childWidth;                 childBottom = childTop + childHeight;                 childView.layout(0, childTop, childRight, childBottom);                 usedWidth = usedWidth + childWidth;                 childLeft = childWidth;                 continue;             }             childRight = childLeft + childWidth;             childBottom = childTop + childHeight;             childView.layout(childLeft, childTop, childRight, childBottom);             childLeft = childLeft + childWidth;             usedWidth = usedWidth + childWidth;          }     }      @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {          //先取出SimpleFlowLayout的父view 對(duì)SimpleFlowLayout 的測(cè)量限制 這一步很重要噢。         //你只有知道自己的寬高 才能限制你子view的寬高         int widthMode = MeasureSpec.getMode(widthMeasureSpec);         int heightMode = MeasureSpec.getMode(heightMeasureSpec);         int widthSize = MeasureSpec.getSize(widthMeasureSpec);         int heightSize = MeasureSpec.getSize(heightMeasureSpec);           int usedWidth = 0;      //已使用的寬度         int remaining = 0;      //剩余可用寬度         int totalHeight = 0;    //總高度         int lineHeight = 0;     //當(dāng)前行高          for (int i = 0; i < getChildCount(); i++) {             View childView = getChildAt(i);             LayoutParams lp = childView.getLayoutParams();              //先測(cè)量子view             measureChild(childView, widthMeasureSpec, heightMeasureSpec);             //然后計(jì)算一下寬度里面 還有多少是可用的 也就是剩余可用寬度             remaining = widthSize - usedWidth;              //如果一行不夠放了,也就是說(shuō)這個(gè)子view測(cè)量的寬度 大于 這一行 剩下的寬度的時(shí)候 我們就要另外啟一行了             if (childView.getMeasuredWidth() > remaining) {                 //另外啟動(dòng)一行的時(shí)候,使用過的寬度 當(dāng)然要設(shè)置為0                 usedWidth = 0;                 //另外啟動(dòng)一行了 我們的總高度也要加一下,不然高度就不對(duì)了                 totalHeight = totalHeight + lineHeight;             }              //已使用 width 進(jìn)行 累加             usedWidth = usedWidth + childView.getMeasuredWidth();             //當(dāng)前 view 的高度             lineHeight = childView.getMeasuredHeight();         }          //如果SimpleFlowLayout 的高度 為wrap cotent的時(shí)候 才用我們疊加的高度,否則,我們當(dāng)然用父view對(duì)如果SimpleFlowLayout 限制的高度         if (heightMode == MeasureSpec.AT_MOST) {             heightSize = totalHeight;         }         setMeasuredDimension(widthSize, heightSize);     } }

關(guān)于Android 中怎么自定義Viewgroup就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

文章題目:Android中怎么自定義Viewgroup
文章地址:http://www.rwnh.cn/article12/jgpsgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、網(wǎng)站營(yíng)銷、搜索引擎優(yōu)化、網(wǎng)站設(shè)計(jì)公司、服務(wù)器托管、品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司
浏阳市| 合阳县| 南靖县| 神木县| 二手房| 海淀区| 湘乡市| 商河县| 寻乌县| 岑溪市| 瓦房店市| 宽城| 顺昌县| 独山县| 玉环县| 江陵县| 当雄县| 霍州市| 宁陵县| 安徽省| 米易县| 布拖县| 山丹县| 勐海县| 兰溪市| 布拖县| 黄梅县| 长白| 垫江县| 平和县| 江都市| 安新县| 沽源县| 祁阳县| 九寨沟县| 宁晋县| 龙里县| 怀安县| 公安县| 永昌县| 略阳县|