Android学习之自定义ViewGroup

1,概述

ViewGroup相当于一个放置VIew的容器,并且我们再写布局xml的时候,会高绿容器(凡是以layout为开头的属性,都是为用于告诉容器的)我们的宽度(layout_width)、高度(layout_height)、对齐方式(layout_gravity)等,当然还有margin
于是,ViewGroup的职能是:给chlidView计算出建议的宽和高和测量模式,决定childView的位置(为什么是建议呢,不是直接给出高和宽,因为childView宽和高可以设置为为wrap_content,这样只有childView才能计算出自己的宽度和高度),
还有个更重要的职责是:在VIewGroup为其指定的区域内绘制自己的形态

ViewGroup和LayoutParams之间的关系?
大家可以回忆一下,当在LinearLayout中写childView的时候,可以写layout_gravity,layout_weight属性;在RelativeLayout中的childView有layout_centerInParent属性,却没有layout_gravity,layout_weight,这是为什么呢?这是因为每个ViewGroup需要指定一个LayoutParams,用于确定支持childView支持哪些属性,比如LinearLayout指定LinearLayout.LayoutParams等。如果大家去看LinearLayout的源码,会发现其内部定义了LinearLayout.LayoutParams,在此类中,你可以发现weight和gravity的身影。

2,View的3种测量模式

EXACTLY:表示设置了精确的值,一般当childView设置其宽,高为精确值,match_parent时,ViewGroup会将其设置为EXACTLY

AT_MOST:表示字布局被限制在一个最大值内,一般当childView设置其宽,高为wrap_content时,

UNSPECIFIED:表示子布局想要多大就多大,一般出现在AdapterView的Item的HeightMode中,ScrollView的childView的heightMode中;此种模式比较少见。

3,从API角度进行浅析

View的根据ViewGroup传人的测量值和模式,对自己宽高进行确定(onMeasure中完成),然后在onDraw中完成对自己的绘制。
ViewGroup需要给View传入view的测量值和模式(onMeasure中完成),而且对于此ViewGroup的父布局,自己也需要在onMeasure中完成对自己宽和高的确定。此外,需要在onLayout中完成对其childView的位置的指定。

4实战

需求:我们定义一个ViewGroup,内部传入四个childView,分别依次显示在四个角角

首先,我们确定该ViewGroup的LayoutParams

 @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(mContext,attrs);
    }

然后我们再onMeasure方法中确定ViewGroup的大小

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        //获取此ViewGroup上级容器所推荐的宽度和高度,及其计算模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeheight = MeasureSpec.getSize(heightMeasureSpec);



        //计算出所有childView的宽和高
        measureChildren(widthMeasureSpec,heightMeasureSpec);

        //如果是wrap_content,设置宽和高
        int  wdith;
        int height;


        mChildCount = getChildCount();
        int cWidth=0;
        int cHeight=0;

        //两者取最大
        int tWidth=0;
        int bWidth=0;

        //两者取最大
        int lHeight=0;
        int rHeight=0;
        MarginLayoutParams layoutParams = null;

        for(int i = 0 ;i < mChildCount;i++){
            View child  = getChildAt(i);
            cWidth = child.getMeasuredWidth();
            cHeight = child.getMeasuredHeight();
            layoutParams =(MarginLayoutParams) child.getLayoutParams();

            if(i == 0 || i ==1){
                tWidth+=(cWidth+layoutParams.leftMargin+layoutParams.rightMargin);
            }

            if(i == 2 || i == 3){
                bWidth +=(cWidth+layoutParams.leftMargin+layoutParams.rightMargin);
            }

            if(i == 0 || i == 2){
                lHeight += (cHeight+layoutParams.topMargin+layoutParams.bottomMargin);
            }

            if(i== 1 || i == 3){
                rHeight += (cHeight+layoutParams.topMargin+layoutParams.bottomMargin);
            }


            wdith = Math.max(tWidth,bWidth);
            height = Math.max(lHeight,rHeight);

            setMeasuredDimension((widthMode == MeasureSpec.EXACTLY)? sizeWidth:wdith
            ,(heightMode == MeasureSpec.EXACTLY)? sizeheight:height);

        }





    }

然后在onLayout方法中,对每一个childView确定位置

 @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        mChildCount = getChildCount();
        int cWdith = 0;
        int cHeight = 0;
        MarginLayoutParams layoutParams = null;

        for(int i = 0; i< mChildCount ;i++){
            View childView  = getChildAt(i);
            cWdith = childView.getMeasuredWidth() ;
            cHeight = childView.getMeasuredHeight();
            layoutParams =(MarginLayoutParams) childView.getLayoutParams();

            int cl = 0, ct = 0, cr = 0,cb = 0;

            switch (i){
                case 0:
                    cl=layoutParams.leftMargin;
                    ct=layoutParams.rightMargin;
                    break;
                case 1 :
                    cl = getWidth()-cWdith-layoutParams.rightMargin;
                    ct = layoutParams.topMargin;
                    break;
                case 2:
                    cl = layoutParams.rightMargin;
                    ct = getHeight()-cHeight-layoutParams.bottomMargin;
                    break;
                case 3:
                    cl = getWidth()-cWdith-layoutParams.rightMargin;
                    ct = getHeight()-cHeight-layoutParams.bottomMargin;
                    break;

            }

            cr = cl+cWdith;
            cb = ct+cHeight;

            childView.layout(cl,ct,cr,cb);
        }


    }

布局:

<com.example.zhy_custom_viewgroup.CustomImgContainer xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="200dp"  
    android:layout_height="200dp"  
    android:background="#AA333333" >  

    <TextView  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="#FF4444"  
        android:gravity="center"  
        android:text="0"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

    <TextView  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="#00ff00"  
        android:gravity="center"  
        android:text="1"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

    <TextView  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="#ff0000"  
        android:gravity="center"  
        android:text="2"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

    <TextView  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="#0000ff"  
        android:gravity="center"  
        android:text="3"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

</com.example.zhy_custom_viewgroup.CustomImgContainer>  

这里写图片描述

布局2:

<com.example.zhy_custom_viewgroup.CustomImgContainer xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"  
    android:background="#AA333333" >  

    <TextView  
        android:layout_width="150dp"  
        android:layout_height="150dp"  
        android:background="#E5ED05"  
        android:gravity="center"  
        android:text="0"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

    <TextView  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="#00ff00"  
        android:gravity="center"  
        android:text="1"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

    <TextView  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="#ff0000"  
        android:gravity="center"  
        android:text="2"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

    <TextView  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="#0000ff"  
        android:gravity="center"  
        android:text="3"  
        android:textColor="#FFFFFF"  
        android:textSize="22sp"  
        android:textStyle="bold" />  

</com.example.zhy_custom_viewgroup.CustomImgContainer>  

这里写图片描述

本文出自:http://blog.csdn.net/lmj623565791/article/details/38339817 , 本文出自:【张鸿洋的博客】

在计算childView的时候,鸿洋大大的博客上有一个小错误,我自己改了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值