(white seconds understand) customize the waterfall layout of ViewGroup

Posted by parena on Sun, 09 Feb 2020 17:19:49 +0100

Let's talk about what I mean by waterfall layout here:

  • There are N textviews, or other views, arranged one by one. Unlike LinearLayout, you can wrap lines
    Take a look at the picture. Otherwise, it's unexpected. The picture is as follows:

Don't think about it. There must be no existing View to use, because you don't know how many lines there are. They are all arranged according to the width of the View. So we use ViewGroup to customize it.

public class MyGridView extends ViewGroup {

    private int interval = 50;//In order to read and write conveniently, padding is used in practice

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

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

    public MyGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //A lot of times, we don't know when to use getMeasuredHeight() or getHeight(). If you don't want to see the source code, remember: after the setMeasuredDimension() method, getMeasuredHeight() has a value, while getHeight() has a value only after the layout.
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//This is a common method to determine the view width and height under onmeasure. Its parameters are passed from the parent layout to the child layout,
        Log.e("----------", "onMeasure:");
        //onMeasure will be called back twice, so this value is better to be local
        int mWidth = 0, mHeight = 0;
        //This method triggers the onMeasure function of all child views to measure the width and height, that is, the getMeasuredHeight method can get the width and height of child views. Don't worry, the above conclusion has not been overturned, because according to the source measureChildren, the setMeasuredDimension() method function can be traced finally. If this method is not called, childview.getMeasuredHeight() in onLayout can't get the value.
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        //MeasureSpec encapsulates the layout requirements passed from the parent View to the child View, namely mode and size
        int wSize = MeasureSpec.getSize(widthMeasureSpec);

        //Calculate the height of the parent view from the height of the child view
        for (int i = 0; i < getChildCount(); i++) {
            Log.e("----------", "i:" + i + ",mWidth:" + mWidth);
            View childView = getChildAt(i);
            if (mWidth + interval + childView.getMeasuredWidth() > wSize) {
                mHeight = (mHeight + interval + childView.getMeasuredHeight());
                Log.e("----------", "mHeight:" + mHeight);
                mWidth = 0;
            }
            mWidth = mWidth + interval + childView.getMeasuredWidth();
            //The height of the last line should be added. There is a better way to welcome mending
            if (i == getChildCount() - 1) {
                if (mWidth > 0 && mWidth < wSize) {
                    mHeight = mHeight+childView.getMeasuredHeight()+interval;
                    Log.e("----------", "mHeight:" + mHeight);
                }
            }
        }
        //Set the width and height of the ViewGroup
        setMeasuredDimension(wSize, mHeight);
        Log.e("----------", "----------------");
    }

    //One by one layout is OK, just control line feed
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int currentx = 0;
        int currenty = 0;
        for (int i = 0; i < getChildCount(); i++) {

            View childView = getChildAt(i);

            if (currentx + childView.getMeasuredWidth() > getWidth()) {
                currenty = (currenty + interval + childView.getMeasuredHeight());
                currentx = 0;
            }
            childView.layout(currentx, currenty, currentx + childView.getMeasuredWidth(), currenty + childView.getMeasuredHeight());
            currentx = currentx + interval + childView.getMeasuredWidth();
        }
    }

    //This method can't be implemented, because we didn't redraw things, just rearranged the View
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

Let's take a look at the layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.a_0102.mylearn.gesture.GesturePwdActivity">
    <!--Be sure to use the full name, i.e. package name+Class name-->
    <com.example.a_0102.mylearn.view.MyGridView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/blue">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Ha ha ha" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="I'm so worried about success and loss" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Many, many, many" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Sobbing sobbing sobbing sobbing sobbing sobbing sobbing sobbing sobbing" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Struggle and struggle" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text=" More and more" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Ha ha ha"
            android:background="@color/colorAccent"/>
    </com.example.a_0102.mylearn.view.MyGridView>

</LinearLayout>

Topics: Android xml encoding