preface

In our practical application, we often need to use custom controls, such as custom circular head, custom pedometer and so on. But sometimes we don’t just need to customize a control, for example, FloatingActionButton is something that people use a lot, so it’s very common for people to want to click on a FloatingActionButton and pop up more FloatingActionButtons, The general idea for this requirement is to write n buttons and then animate them one by one. But this is really too much trouble, so there is an open source library on the Internet, which uses the custom layout “ViewGroup”. Now let me introduce to his family how to customize the layout “Layout”.


The difficulties in

Compared with a custom View, the difficulty of a custom ViewGroup lies in the determination of the location of child controls and the size of the layout. A ViewGroup’s width varies depending on the number of subviews and the size of the individual views. That’s the biggest hurdle, so how do you determine the size of a ViewGroup?


steps

Here I design a ViewGroup similar to a LinearLayout as an example.

First of all, if it’s a LinearLayout then when you set wrAP_content, it’s going to take the width of the largest subspace. The height is also the sum of the heights of all child controls. So let’s write two methods to measure the width and height of the ViewGroup.


    private int getMaxWidth(a){
        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(a){
        int count = getChildCount();
        int totalHeight = 0;
        for (int i = 0 ; i < count ; i++){
            totalHeight += getChildAt(i).getMeasuredHeight();
        }
        return totalHeight;
    }
    
Copy the code

ViewGroup can be roughly divided into two modes: fixed width mode (match_parent) and adaptive mode (wrap_content). According to these two modes, ViewGroup drawing can be divided. The measureChildren method is used to measure all of the child views, which triggers the onMeasure function of each child View, but it must be distinguished from measureChild. MeasureChild measures a single View

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
        measureChildren(widthMeasureSpec, heightMeasureSpec);
 
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width     = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode= MeasureSpec.getMode(heightMeasureSpec);
        int height    = MeasureSpec.getSize(heightMeasureSpec);
 
        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(), height);
        }else if(heightMode == MeasureSpec.AT_MOST){ setMeasuredDimension(width, getTotalHeight()); }}Copy the code

Override onLayout

Now we have a layout size of 79, so let’s add it to the layout file of the activity, add a few sub-views and run it to see what it looks like:

    <com.entry.android_view_user_defined_first.views.MyLinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent">
 
        <Button
            android:layout_width="100dp"
            android:layout_height="50dp"
            android:text="qwe"/>
 
        <Button
            android:layout_width="250dp"
            android:layout_height="150dp"
            android:text="qwe"/>
 
        <Button
            android:layout_width="200dp"
            android:layout_height="75dp"
            android:text="qwe"/>
 
    </com.entry.android_view_user_defined_first.views.MyLinearLayout>
Copy the code

The running effect is as follows:

We see that the layout is out, and the size seems to be fine, but what about the sub-view? ! The onLayout() we rewrote is still empty. In other words, the size and position of the child View have not been set at all! Let’s rewrite the onLayout() method.

    @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();
            intwidth = view.getMeasuredWidth(); view.layout(l, currentHeight, l + width, currentHeight + height); currentHeight += height; }}Copy the code

Let’s run it again:

It worked!

Since this article is a summary of my own learning process, I hope you can point out any mistakes in the comments section

Finally, have fun programming!