自定义ViewGroup-自定义LayoutParams支持显示方位

来源:互联网 发布:linux 开启snmp 编辑:程序博客网 时间:2024/05/06 13:44

自定义属性:

<resources>    <declare-styleable name="CustomViewGroup5">        <attr name="layout_position" format="enum">            <enum name="left_top" value="0" />            <enum name="right_top" value="1" />            <enum name="left_bottom" value="2" />            <enum name="right_bottom" value="3" />        </attr>    </declare-styleable></resources>

方位包含 4 个方向:左上角、右上角、左下角、右下角,在 attrs.xml 文件中,定义一个名为layout_position 的属性,类型为 enum,枚举出这 4 个值。



activity_main:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:custom="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:padding="10dp">    <com.example.user.myapplication4.CustomViewGroup5        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="#FFCCCCCC"        android:padding="10dp">        <TextView            android:layout_width="100dp"            android:layout_height="100dp"            android:layout_margin="10dp"            android:background="@android:color/holo_blue_bright"            android:gravity="center"            android:text="A"            android:textColor="#FFFFFFFF"            custom:layout_position="right_bottom" />        <TextView            android:layout_width="100dp"            android:layout_height="100dp"            android:background="@android:color/holo_blue_dark"            android:gravity="center"            android:text="B"            android:textColor="#FFFFFFFF"            custom:layout_position="left_bottom" />        <TextView            android:layout_width="100dp"            android:layout_height="100dp"            android:layout_margin="10dp"            android:background="@android:color/holo_red_dark"            android:gravity="center"            android:text="C"            android:textColor="#FFFFFFFF"            custom:layout_position="right_top" />        <TextView            android:layout_width="100dp"            android:layout_height="100dp"            android:background="@android:color/holo_green_light"            android:gravity="center"            android:text="D"            android:textColor="#FFFFFFFF"            custom:layout_position="left_top" />    </com.example.user.myapplication4.CustomViewGroup5></LinearLayout>


CustomViewGroup5:

public class CustomViewGroup5 extends ViewGroup {    public CustomViewGroup5(Context context) {        super(context);    }    public CustomViewGroup5(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public CustomViewGroup5(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    /**     * @param attrs     * @return     */    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        Log.i("log", "generateLayoutParams:AttributeSet");        return new PositionLayoutParams(this.getContext(), attrs);    }    @Override    protected LayoutParams generateLayoutParams(LayoutParams p) {        Log.i("log", "generateLayoutParams:LayoutParams");        return new PositionLayoutParams(p);    }    /**     * @return     */    @Override    protected LayoutParams generateDefaultLayoutParams() {        Log.i("log", "generateDefaultLayoutParams");        return new PositionLayoutParams(LayoutParams.WRAP_CONTENT,                LayoutParams.WRAP_CONTENT);    }    /**     * 自定义LayoutParams     */    public static class PositionLayoutParams extends ViewGroup.MarginLayoutParams {        public static final int LEFT_TOP = 0;        public static final int RIGHT_TOP = 1;        public static final int LEFT_BOTTOM = 2;        public static final int RIGHT_BOTTOM = 3;        public static final int NONE = -1;        public int position;        public PositionLayoutParams(Context c, AttributeSet attrs) {            super(c, attrs);            TypedArray typedArray = c.obtainStyledAttributes(attrs, R.styleable.CustomViewGroup5);            position = typedArray.getInt(R.styleable.CustomViewGroup5_layout_position, NONE);            typedArray.recycle();        }        public PositionLayoutParams(int width, int height) {            super(width, height);        }        public PositionLayoutParams(MarginLayoutParams source) {            super(source);        }        public PositionLayoutParams(LayoutParams source) {            super(source);        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //测量所有的子View        measureChildren(widthMeasureSpec, heightMeasureSpec);        //测量自己的宽高        int width = measureWidth(widthMeasureSpec);        int height = measureHeight(heightMeasureSpec);        setMeasuredDimension(width, height);    }    private int measureHeight(int widthMeasureSpec) {        //父控件建议自己测量的值        int measureMode = MeasureSpec.getMode(widthMeasureSpec);        int measureSize = MeasureSpec.getSize(widthMeasureSpec);        int width = 0;        if (measureMode == MeasureSpec.EXACTLY) {            width = measureSize;        } else if (measureMode == MeasureSpec.AT_MOST) {            int aWidth = 0;            int bWidth = 0;            int cWidth = 0;            int dWidth = 0;            int haMargin = 0;            int hbMargin = 0;            int hcMargin = 0;            int hdMargin = 0;            for (int i = 0; i < getChildCount(); i++) {                MarginLayoutParams layoutParams = (MarginLayoutParams) getChildAt(i).getLayoutParams();                if (i == 0) {                    aWidth = getChildAt(i).getMeasuredWidth();//左边View的宽度                    haMargin += layoutParams.topMargin + layoutParams.bottomMargin;                } else if (i == 1) {                    bWidth = getChildAt(i).getMeasuredWidth();                    hbMargin += layoutParams.topMargin + layoutParams.bottomMargin;                } else if (i == 2) {                    cWidth = getChildAt(i).getMeasuredWidth();                    hcMargin += layoutParams.topMargin + layoutParams.bottomMargin;                } else if (i == 3) {                    dWidth = getChildAt(i).getMeasuredWidth();                    hdMargin = layoutParams.topMargin + layoutParams.bottomMargin;                }            }            //getPaddingTop:top离top的内边距   getPaddingBottom:bottom离底的内边距            width = Math.max(aWidth, bWidth) + Math.max(cWidth, dWidth)                    + getPaddingTop() + getPaddingBottom()                    + Math.max(haMargin, hbMargin) + Math.max(hcMargin, hdMargin);//取到宽度的最大值        }        return width;    }    private int measureWidth(int heightMeasureSpec) {        int measureMode = MeasureSpec.getMode(heightMeasureSpec);        int measureSize = MeasureSpec.getSize(heightMeasureSpec);        int height = 0;        if (measureMode == MeasureSpec.EXACTLY) {            height = measureSize;        } else if (measureMode == MeasureSpec.AT_MOST) {            int aHeight = 0;            int bHeight = 0;            int cHeight = 0;            int dHeight = 0;            int waMargin = 0;            int wbMargin = 0;            int wcMargin = 0;            int wdMargin = 0;            for (int i = 0; i < getChildCount(); i++) {                MarginLayoutParams layoutParams = (MarginLayoutParams) getChildAt(i).getLayoutParams();                if (i == 0) {                    aHeight = getChildAt(i).getMeasuredHeight();                    waMargin = layoutParams.leftMargin + layoutParams.rightMargin;                } else if (i == 1) {                    bHeight = getChildAt(i).getMeasuredHeight();                    wbMargin = layoutParams.leftMargin + layoutParams.rightMargin;                } else if (i == 2) {                    cHeight = getChildAt(i).getMeasuredHeight();                    wcMargin = layoutParams.leftMargin + layoutParams.rightMargin;                } else if (i == 3) {                    dHeight = getChildAt(i).getMeasuredHeight();                    wdMargin = layoutParams.leftMargin + layoutParams.rightMargin;                }            }            height = Math.max(aHeight, bHeight) + Math.max(cHeight, dHeight)                    + getPaddingLeft() + getPaddingRight()                    + Math.max(waMargin, wbMargin) + Math.max(wcMargin, wdMargin);//取到宽度的最大值        }        return height;    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int leftPadding = getPaddingLeft();        int rightPadding = getPaddingRight();        int topPadding = getPaddingTop();        int bottomPadding = getPaddingBottom();        for (int i = 0; i < getChildCount(); i++) {            View childView = getChildAt(i);//某一个子View            PositionLayoutParams layoutParams = (PositionLayoutParams) childView.getLayoutParams();            int leftMargin = layoutParams.leftMargin;            int topMargin = layoutParams.topMargin;            int rightMargin = layoutParams.rightMargin;            int bottomMargin = layoutParams.bottomMargin;            int position = layoutParams.position;            if (i == 0 && position == PositionLayoutParams.NONE || position == PositionLayoutParams.LEFT_TOP) {                childView.layout(leftPadding + leftMargin,                        topPadding + topMargin,                        childView.getMeasuredWidth() + leftPadding + leftMargin,                        childView.getMeasuredHeight() + topPadding + topMargin);            } else if (i == 1 && position == PositionLayoutParams.NONE                    || layoutParams.position ==                    PositionLayoutParams.RIGHT_TOP) {                childView.layout(getMeasuredWidth() - childView.getMeasuredWidth() - rightPadding - rightMargin,                        topPadding + topMargin,                        getMeasuredWidth() - rightPadding - rightMargin,                        childView.getMeasuredHeight() + topPadding + topMargin);            } else if (i == 2 && position == PositionLayoutParams.NONE                    || layoutParams.position ==                    PositionLayoutParams.LEFT_BOTTOM) {                childView.layout(leftPadding + leftMargin,                        getMeasuredHeight() - childView.getMeasuredHeight()                                - bottomPadding - bottomMargin,                        childView.getMeasuredWidth() + leftPadding + leftMargin,                        getMeasuredHeight() - bottomPadding - bottomMargin);            } else if (i == 3 && position == PositionLayoutParams.NONE                    || layoutParams.position ==                    PositionLayoutParams.RIGHT_BOTTOM) {                childView.layout(getMeasuredWidth() - childView.getMeasuredWidth() - rightPadding - rightMargin,                        getMeasuredHeight() - childView.getMeasuredHeight() - bottomPadding - bottomMargin,                        getMeasuredWidth() - rightPadding - rightMargin,                        getMeasuredHeight() - bottomPadding - bottomMargin);            }        }    }}

PositionLayoutParams(Context c, AttributeSet attrs)读取了 layout_position 属性值,保存在 position成员变量中,如果未读取到该属性,则默认值为 NONE。其次定义了 4 个常量与 layout_position属性的 4 个枚举值相对应。ViewGroup 类重写的 generateLayoutParams()和 generateDefaultLayoutParams()方法返回的LayoutParams 为 PositionLayoutParams 对象。 其 中 public LayoutParams generateLayoutParams(AttributeSetattrs)方法将 attrs 传入 public PositionLayoutParams(Context c, AttributeSet attrs)构造方法,所以,PositionLayoutParams 才能读取到 layout_position 的属性值。在 onLayout()方法中,我们需要根据当前子组件的 PositionLayoutParams 的 position 属性来确定方位,这里有两种情况:一种是没有为组件定义方位时,依旧按照从左往右、从上往下的方式进行放置;另一种是如果组件定义了特定方位,如 right_bottom,则将该组件显示在容器的右下角。



结果显示:



0 0