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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32113133/article/details/65445735

自定义属性:

<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,则将该组件显示在容器的右下角。



结果显示:



猜你喜欢

转载自blog.csdn.net/qq_32113133/article/details/65445735
今日推荐