美文网首页
自定义ViewGroup详解

自定义ViewGroup详解

作者: kjy_112233 | 来源:发表于2018-09-18 17:49 被阅读0次

一、ViewGroup

(1)常用方法

  • CustomViewGroup(Context context):在Java代码中new时调用
  • CustomViewGroup(Context context, AttributeSet attrs):在xml布局文件中使用时自动调用
  • generateLayoutParams(AttributeSet attrs):设置ViewGroup关联字View的属性
  • onMeasure(int widthMeasureSpec, int heightMeasureSpec):计算子View宽高以及设置自己的宽高
  • onLayout(boolean changed, int l, int t, int r, int b):设置子View的布局的位置
  • onTouchEvent(MotionEvent event):监听触摸事件

(2)自定义属性

  • 在values/attrs.xml自定义属性名称和取值类型
<resources>
    <declare-styleable name="customViewGroup">
        <attr name="horizontal_space" format="dimension"></attr>
        <attr name="vertical_space" format="dimension"></attr>
    </declare-styleable>
</resources>
  • 在构造方法中获得自定义属性的值

(3)onMeasure与onLayout

  • onMeasure测量计算子View宽高以及设置自己的宽高
    EXACTLY:精确模式
    AT_MOST:至多不超过模式
    UNSPECIFIED:不确定模式
    measureChildren:对所有的子View进行测量
    measureChild:对单个View进行测量
  • onLayout设置子View的大小与位置
    getChildCount:获取子View的个数
    getChildAt:获取单个子View

(4)自定义ViewGroup实现

  • 重写onMeasure方法确定CustomViewGroup大小
  • 重写generateLayoutParams方法设置LayoutParams为MarginLayoutParams
  • 重写onLayout方法循环遍历子View
public class CustomViewGroup extends ViewGroup {

    public CustomViewGroup(Context context) {
        super(context);
    }

    public CustomViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        //判断当前设置是否是wrap_content
        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            int groupWidth = getMaxWidth();
            int groupHeight = getTotalHeight();
            setMeasuredDimension(groupWidth, groupHeight);
        } else if (widthMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(getMaxWidth(), heightSize);
        } else if (heightMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSize, getTotalHeight());
        }
    }

    private int getMaxWidth() {
        int count = getChildCount();
        int maxWidth = 0;
        for (int i = 0; i < count; i++) {
            int currentWidth = getChildAt(i).getMeasuredWidth();
            if (maxWidth < currentWidth)
                maxWidth = currentWidth;
        }
        return maxWidth;
    }

    private int getTotalHeight() {
        int count = getChildCount();
        int totalHeight = 0;
        for (int i = 0; i < count; i++) {
            totalHeight += getChildAt(i).getMeasuredHeight();
        }
        return totalHeight;
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int count = getChildCount();
        int currentHeight = 0;
        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            int height = view.getMeasuredHeight();
            int width = view.getMeasuredWidth();
            view.layout(l, currentHeight, l + width, currentHeight + height);
            currentHeight += height;
        }
    }
}

(5)自定义ViewGroup自动换行

  • 在CustomViewGroup构造方法中自定义属性
  • 在onMeasure方法中测量ViewGroup控件的宽高
  • 在onLayout方法中确定子View的位置
public class CustomViewGroup extends ViewGroup {
    private int count;
    //子View上方距离
    private int marginTop;
    //子View左侧距离
    private int marginLeft;
    //子View中上下的空闲区域
    private int paddingTop;
    //子View中左右的空闲区域
    private int paddingLeft;

    public CustomViewGroup(Context context) {
        this(context, null);
    }

    public CustomViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        @SuppressLint("CustomViewStyleable")
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customViewGroup);
        marginTop = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_margin_top, 0);
        marginLeft = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_margin_left, 0);
        paddingTop = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_padding_top, 0);
        paddingLeft = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_padding_left, 0);
        typedArray.recycle();
    }


    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int rowNumber = 1;
        int totalWidth = 0;
        int totalHeight = 0;
        count = getChildCount();
        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            view.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop);
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
            totalWidth += (width + marginLeft);
            if (totalWidth > widthSize) {
                totalWidth = (width + marginLeft);
                rowNumber++;
            }
            totalHeight = rowNumber * (height + marginTop);
        }
        setMeasuredDimension(widthSize, totalHeight);
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int rowNumber = 1;
        int totalWidth = 0;
        int totalHeight;
        int actualWidth = r - l;
        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            int width = getChildAt(i).getMeasuredWidth();
            int height = getChildAt(i).getMeasuredHeight();
            totalWidth += (width + marginLeft);
            if (totalWidth > actualWidth) {
                totalWidth = (width + marginLeft);
                rowNumber++;
            }
            totalHeight = rowNumber * (height + marginTop);
            view.layout(totalWidth - width, totalHeight - height, totalWidth, totalHeight);
        }
    }
}

相关文章

网友评论

      本文标题:自定义ViewGroup详解

      本文链接:https://www.haomeiwen.com/subject/ainlnftx.html