自定义ViewGroup及其属性

来源:互联网 发布:me544j支持什么网络 编辑:程序博客网 时间:2024/05/29 08:06

闲来无事自定义个viewGroup的控件来练练手。

比如说现在有这么个需求,一左一右分别有个textView,然后外面一个控件直接包裹这两个;

1:现在给这个自定义控件(本文中名叫RcLinearLayout)自定义一个属性,然后去通过这个属性去确定这两个textView是否需要处于同一水平线上。

①先建立values文件夹下的attrs.xml文件,如:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="c_view">        <attr name="gravity">            <enum name="CENTER_VERTICAL" value="0"/>        </attr>    </declare-styleable></resources>
当然了,你还可以增加别的属性,然后根据你设的属性去确定child的位置

2.重要的地方来了,就是自定义控件了,主要是重写onMeasure方法和onLayout方法,onMeasure方法主要是测量出容器的宽与高,而onlayout方法则是确定child的位置,代码如下:

public class RcLinearLayout extends ViewGroup{    private int mGravity;//这个用来标记布局中是否设置了垂直居中的属性    public RcLinearLayout(Context context) {        this(context,null);    }    public RcLinearLayout(Context context, AttributeSet attrs) {        this(context,attrs,0);    }    public RcLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.c_view);        mGravity = ta.getInt(R.styleable.c_view_gravity,-1);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //获得此控件的宽和高,以及计算模式        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //计算所有child的高和宽        measureChildren(widthMeasureSpec,heightMeasureSpec);        //记录如果是wrap_content是设置的宽和高        int width = 0;        int height = 0;        int cCount = getChildCount();        int cWidth = 0;        int cHeight = 0;        MarginLayoutParams cParams = null;        // 用于计算左边的childView的高度        int lHeight = 0;        // 用于计算右边的childView的高度,最终高度取二者之间大值        int rHeight = 0;        // 用于计算两个childView的宽度        int tWidth = 0;        /**         * 根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时         */        for (int i = 0; i < cCount; i++) {            View childView = getChildAt(i);            cWidth = childView.getMeasuredWidth();            cHeight = childView.getMeasuredHeight();            cParams = (MarginLayoutParams) childView.getLayoutParams();            // 得出两个childView的宽            tWidth += cWidth + cParams.leftMargin + cParams.rightMargin;            if(i==0) {                lHeight += cHeight + cParams.topMargin + cParams.bottomMargin;            }else {                rHeight +=cHeight + cParams.topMargin +cParams.bottomMargin;            }        }        //高取两个childView的取大值        height = Math.max(lHeight,rHeight);        width = tWidth;        /**         * 如果是wrap_content设置为我们计算的值         * 否则:直接设置为父容器计算的值         */        setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : width,                (heightMode == MeasureSpec.EXACTLY) ? sizeHeight : height);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int cCount = getChildCount();        int cWidth = 0;        int cHeight = 0;        MarginLayoutParams cParams = null;//这个用来获取child的参数        //遍历所有childView根据其宽和高,以及margin进行布局        for (int i = 0; i < cCount; i++){            View childView = getChildAt(i);            cWidth = childView.getMeasuredWidth();            cHeight = childView.getMeasuredHeight();            cParams = (MarginLayoutParams) childView.getLayoutParams();            int cl = 0, ct = 0, cr = 0, cb = 0;            if(mGravity==-1) {                switch (i) {                    case 0://第一个childview                        cl = cParams.leftMargin + getPaddingLeft();                        ct = cParams.topMargin + getPaddingTop();                        break;                    case 1://第二个childview                        cl = getWidth() - cWidth - cParams.leftMargin - cParams.rightMargin - getPaddingRight();                        ct = cParams.topMargin + getPaddingTop();                        break;                }            }else            switch (i){                case 0:                    cl = cParams.leftMargin + getPaddingLeft();                    ct = getHeight()/2-cHeight/2;                    break;                case 1:                    cl = getWidth() - cWidth - cParams.leftMargin - cParams.rightMargin - getPaddingRight();                    ct = getHeight()/2-cHeight/2;                    break;            }            cr = cl + cWidth;            cb = cHeight + ct;            childView.layout(cl, ct, cr, cb);        }    }    @Override    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(getContext(), attrs);    }}
3.接下来是在布局文件中使用了
<?xml version="1.0" encoding="utf-8"?><com.example.administrator.CustomView.widget.RcLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:c_view="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="60dp"    android:background="#123456"    c_view:gravity="CENTER_VERTICAL">    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="昵称" />    <TextView        android:id="@+id/id_tv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="赵四"        android:textSize="24sp" /></com.example.administrator.CustomView.widget.RcLinearLayout>    
嗯,基本上就这么多了。


0 0
原创粉丝点击