Andoird 自定义ViewGroup

来源:互联网 发布:北京房山网络职业学院 编辑:程序博客网 时间:2024/06/02 03:20

1.自定义ViewGroup

主要关注两点测量和布局:
onMeasure
测量和保存各个视图和子视图的位置信息
onLayout
遍历所有子视图绘制

2.构造函数

1.res/values/attrs.xml
自定义视图的属性

<?xml version="1.0" encoding="utf-8" ?><resources>    <declare-styleable name="CascadeLayout">        <attr name="horizontal_spacing" format="dimension" />        <attr name="vertical_spacing" format="dimension" />    </declare-styleable></resources>

2.res/values/dimens.xml
自定义视图属性的默认值

<resources>    <dimen name="horizontal_spacing">16dp</dimen>    <dimen name="vertical_spacing">16dp</dimen></resources>
  1. java 代码中使用。
   private int mHorizontalSpacing;    private int mVerticalSpacing;    public CascadeLayout(Context context, AttributeSet attributeSet) {        super(context, attributeSet);        TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.CascadeLayout);        try {            mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.CascadeLayout_horizontal_spacing, getResources().getDimensionPixelSize(R.dimen.horizontal_spacing));            mVerticalSpacing = a.getDimensionPixelSize(R.styleable.CascadeLayout_vertical_spacing, getResources().getDimensionPixelSize(R.dimen.vertical_spacing));        } finally {            a.recycle();        }    }

3. 布局 写法

  1. 自定义属性使用
    命名空间
    a)eclipse写法,android studio也适用
    类似系统自带属性命名空间 xmlns:android=”http://schemas.android.com/apk/res/android”
    将res/android 换成你自定义view 所属的包名
    xmlns:cascade=”http://schemas.android.com/apk/com.lq.viewpractice.viewgroup.CascadeLayout”

b)android studio写法,eclipse 不能用

使用res-auto
xmlns:cascade=”http://schemas.android.com/apk/res-auto”

引用lib 和自定义的view 都智能用res-auto

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:cascade="http://schemas.android.com/apk/com.lq.viewpractice.viewgroup.CascadeLayout"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.lq.viewpractice.ViewGroupTestActivity">    <com.lq.viewpractice.viewgroup.CascadeLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        cascade:horizontal_spacing="30dp"        cascade:vertical_spacing="20dp">        <View            android:layout_width="100dp"            android:layout_height="150dp"            android:background="#FF0000" />        <View            android:layout_width="100dp"            android:layout_height="150dp"            android:background="#00FF00" />        <View            android:layout_width="100dp"            android:layout_height="150dp"            android:background="#0000FF" />    </com.lq.viewpractice.viewgroup.CascadeLayout></RelativeLayout>

4. 自定义LayoutParams

这个类的用途就是保存每个子视图的x,y轴位置。这里把它定义为静态内部类。

    public static class LayoutParams extends ViewGroup.LayoutParams {        int x;        int y;        public int verticalSpacing;        public LayoutParams(Context context, AttributeSet attrs) {            super(context, attrs);        }        public LayoutParams(int w, int h) {            super(w, h);        }    }

除此之外,还需要重写一些方法,checkLayoutParams()、generateDefaultLayoutParams()等,这个方法在不同ViewGroup之间往往是相同的。

    @Override    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {        return p instanceof LayoutParams;    }    @Override    protected LayoutParams generateDefaultLayoutParams() {        return new LayoutParams(LayoutParams.WRAP_CONTENT,                LayoutParams.WRAP_CONTENT);    }    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new LayoutParams(getContext(), attrs);    }    @Override    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {        return new LayoutParams(p.width, p.height);    }

5. 核心代码 测量 onMeasure

测量子视图的坐标。

    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int width = getPaddingLeft();        int height = getPaddingTop();        int verticalSpacing;        final int count = getChildCount();        for (int i = 0; i < count; i++) {            verticalSpacing = mVerticalSpacing;            View child = getChildAt(i);            measureChild(child, widthMeasureSpec, heightMeasureSpec);            LayoutParams lp = (LayoutParams) child.getLayoutParams();            width = getPaddingLeft() + mHorizontalSpacing * i;            //保存每个子视图的x,y轴坐标            lp.x = width;            lp.y = height;            if (lp.verticalSpacing >= 0) {                verticalSpacing += lp.verticalSpacing;            }            width += width;            height += verticalSpacing;        }        width += getPaddingRight();        height += getChildAt(getChildCount() - 1).getMeasuredHeight() + getPaddingBottom();        setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));    }

6.核心代码 布局 onLayout

循环调用子view 布局。

    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        final int count = getChildCount();        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            LayoutParams lp = (LayoutParams) child.getLayoutParams();            child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());        }    }

7. 参考链接

http://www.w2bc.com/Article/59242

http://blog.csdn.net/manoel/article/details/39062737

8.demo地址

0 0
原创粉丝点击