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

自定义属性:


    
        
            
            
            
            
        
    

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



activity_main:



    

        

        

        

        
    


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



结果显示:

自定义ViewGroup-自定义LayoutParams支持显示方位_第1张图片

你可能感兴趣的:(Android,自定义控件)