android -------- ViewGroup of custom control

The previous several articles talked about the composite control of custom control, address: https://my.oschina.net/zhangqie/blog/1806507

 

Today's post focuses on the ViewGroup of custom controls.

 

What is ViewGroup?

View Group is a container. It contains zero or more views and subviews

 

What is the role of ViewGroup?

The ViewGroup can be used to store multiple View controls, measure the View sub controls according to its own measurement mode, and determine the location of the View sub controls. This step-by-step explains how it measures and determines the size and location of the child controls.

 

Custom control

public class FlowLayoutb extends ViewGroup {

    private int horizontolSpacing;
    private int verticalSpacing;

    public FlowLayoutb(Context context) {
        super(context);
        init(context);
    }

    public FlowLayoutb(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private Line currentline;// Current row
    private int useWidth = 0;// Width used by the current row
    private List<Line> mLines = new ArrayList<Line>();
    private int width;

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

    private void init(Context context) {
        horizontolSpacing = Util.dip2px(13, context);
        verticalSpacing = Util.dip2px(13, context);
    }

    // Measure the current control Flowlayout
    // The parent class is obliged to measure each child View
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mLines.clear();
        currentline = null;
        useWidth = 0;

        /**
         * Get the width and height recommended by the parent container of this ViewGroup, and the calculation mode
         */
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        // Calculate the width and height of all childviews
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
        int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom() - getPaddingTop(); // Get width and height
        int childeWidthMode;
        int childeHeightMode;
        //  In order to measure each subview, each subview measurement rule needs to be specified
        childeWidthMode = widthMode == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : widthMode;
        childeHeightMode = heightMode == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : heightMode;
        int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childeWidthMode, width);
        int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childeHeightMode, height);
        currentline = new Line();// First line created
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            // Measure each child View
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            int measuredWidth = child.getMeasuredWidth();
            useWidth += measuredWidth;// Add the length used to the current row
            if (useWidth <= width) {
                currentline.addChild(child);//At this time, it is proved that the current subview can be put into the current row and put into it
                useWidth += horizontolSpacing;
            } else {
                //Line feed
                newLine(child);
            }
        }

        if (!mLines.contains(currentline)) {
            mLines.add(currentline);// Add last line
        }
        int totalheight = 0;
        for (Line line : mLines) {
            totalheight += line.getHeight();
        }
        totalheight += verticalSpacing * (mLines.size() - 1) + getPaddingTop() + getPaddingBottom();

        System.out.println(totalheight);
        setMeasuredDimension(width + getPaddingLeft() + getPaddingRight(), resolveSize(totalheight, heightMeasureSpec));
    }

    private void newLine(View child) {
        mLines.add(currentline);// Record previous lines
        currentline = new Line();// Create a new row
        currentline.addChild(child);
        useWidth = currentline.lineWidth;
    }

    private class Line {
        int height = 0; //Height of current row
        int lineWidth = 0;
        private List<View> children = new ArrayList<View>();

        /**
         * Add a child View
         *
         * @param child
         */
        public void addChild(View child) {
            children.add(child);
            if (child.getMeasuredHeight() > height) {
                height = child.getMeasuredHeight();
            }
            lineWidth += child.getMeasuredWidth();
        }

        public int getHeight() {
            return height;
        }

        /**
         * Returns the number of child views
         *
         * @return
         */
        public int getChildCount() {
            return children.size();
        }

        public void layout(int l, int t) {
            lineWidth += horizontolSpacing * (children.size() - 1);
            int surplusChild = 0;
            int surplus = width - lineWidth;
            if (surplus > 0 && children.size() > 0) {
                surplusChild = surplus / children.size();
            }
            for (int i = 0; i < children.size(); i++) {
                View child = children.get(i);
                child.layout(l, t, l + child.getMeasuredWidth() + surplusChild, t + child.getMeasuredHeight());
                l += child.getMeasuredWidth() + surplusChild;
                l += horizontolSpacing;
            }
        }

    }

    // Assign the location of each child View
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        l += getPaddingLeft();
        t += getPaddingTop();
        for (int i = 0; i < mLines.size(); i++) {
            Line line = mLines.get(i);
            line.layout(l, t);  //To each line
            t += line.getHeight() + verticalSpacing;
        }
    }

}

To customize the ViewGroup:

  1. Inherit ViewGroup, override construction method
  2. Overriding the onMeasure method to measure the width and height of child controls and themselves
  3. Implement onLayout method to place child controls

 

 

Design sketch:

 

 

 

 

Source address: https://github.com/DickyQie/android-custom-control

 

reference material:

https://blog.csdn.net/shineflowers/article/details/48055879

https://blog.csdn.net/zxt0601/article/details/50533658

https://blog.csdn.net/shakespeare001/article/details/51089453

Tags: github Android

Posted on Fri, 20 Mar 2020 16:02:46 -0400 by mmtalon