Recently, I have been learning about custom View and custom ViewGroup. Today, I have nothing to do but study FlowLayout and record the implementation steps, referring to hongyang blog

AndroidStudio use

Add in build.gradle at root projcet.

maven { url 'https://jitpack.io' }

Add the following to your project build.gradle:

The compile 'com. Making. SuperSp: FlowLayout: 1.0'

Github has the source code to view

The renderings are self-adaptive





PNG.

Effect drawing fixed size





PNG.

Use method – static add

<lsp.com.library.FlowLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView style="@style/text_flag_01" Android :text="Welcome" /> <TextView style="@style/text_flag_01" Android :text="IT engineer "/> <TextView Style ="@style/text_flag_01" Android :text=" learning "/> <TextView style="@style/text_flag_01" Android :text=" love" /> <TextView style="@style/text_flag_02" Android :text=" love "/> <TextView style="@style/text_flag_02" Android :text=" earn money" /> <TextView style="@style/text_flag_02" Android :text=" hard ing" /> <TextView style="@style/text_flag_02" Android :text="I Thick can "/ > < / lsp.com.library.FlowLayout > style file:  <style name="text_flag_01"> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> <item name="android:layout_margin">5dp</item> <item Name ="android:background">@drawable/flag_01</item> </style> Style 1 (flag_01) <? XML version = "1.0" encoding = "utf-8"? > < shape XMLNS: android = "http://schemas.android.com/apk/res/android" > <solid android:color="#7690A5"/> <corners android:radius="5dp"/> <padding android:bottom="2dp" android:left="2dp" Android :right="2dp" Android :top="2dp"/> </shape> Style 2 (FLAG_02) <? XML version="1.0" encoding=" UTF-8 "?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="#E7E7E7" > </solid> <corners android:radius="30dp" /> <padding android:bottom="2dp" android:left="10dp" android:right="10dp" android:top="2dp" /> </shape> Whatever you like ~~Copy the code

Use method – dynamic add

FlowLayout flowLayout = new FlowLayout(this); Flowlayout.initdata (Arrays. AsList ("Welcome","IT Engineer "," Learn ing"," Love ing"," Earn ing"," Work hard ","I thick I Can "); setContentView(flowLayout);Copy the code

InitData method

public void initData(List<String> list)
public void initData(List<String> list, int margin, int drawable)Copy the code

Add click events

flowLayout.setOnTabClickListener(new FlowLayout.IOnTabClickListener() { @Override public void onTabClick(int position, TextView textView) { Toast.makeText(Test.this,position+" "+textView.getText(),Toast.LENGTH_SHORT).show(); }}); setContentView(flowLayout);Copy the code

Implementation approach

A constructor
    public FlowLayout(Context context) {
        this(context, null);
    }

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

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }Copy the code
The child view supports the margin property
 @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }Copy the code

OnMeasure method

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); MeasureChildren (widthMeasureSpec, heightMeasureSpec); Int width = 0; int height = 0; Int lineWidth = 0; Int cCount = getChildCount(); View cView; MarginLayoutParams params; int cWidth, cHeight; for (int i = 0; i < cCount; i++) { cView = getChildAt(i); params = (MarginLayoutParams) cView.getLayoutParams(); cWidth = cView.getMeasuredWidth() + params.leftMargin + params.rightMargin; cHeight = cView.getMeasuredHeight() + params.topMargin + params.bottomMargin; ViewBean viewBean = new ViewBean(); if (lineWidth + cWidth < widthSize) { lineWidth += cWidth; height = Math.max(height, cHeight); width = Math.max(lineWidth, width); } else { width = Math.max(lineWidth, width); height += cHeight; lineWidth = cWidth; } viewBean.setLeft(lineWidth - cWidth + params.leftMargin); viewBean.setTop(height - cHeight + params.topMargin); viewBean.setRight(lineWidth - params.rightMargin); viewBean.setBottom(height - params.bottomMargin); list.add(viewBean); } setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width, heightMode == MeasureSpec.EXACTLY ? heightSize : height); }Copy the code
OnLayout method
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { getChildAt(i).layout(list.get(i).getLeft(), list.get(i).getTop(), list.get(i).getRight(), list.get(i).getBottom()); }}Copy the code
Viewbeans method
private class ViewBean { private int left; private int right; private int top; private int bottom; public int getLeft() { return left; } public void setLeft(int left) { this.left = left; } public int getRight() { return right; } public void setRight(int right) { this.right = right; } public int getTop() { return top; } public void setTop(int top) { this.top = top; } public int getBottom() { return bottom; } public void setBottom(int bottom) { this.bottom = bottom; }}Copy the code
Dynamic data filling implementation
public void initData(List<String> list) { ViewGroup.MarginLayoutParams pa = new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.WRAP_CONTENT, ViewGroup.MarginLayoutParams.WRAP_CONTENT); int size = list.size(); for (int i = 0; i < size; i++) { TextView tv = new TextView(getContext()); tv.setText(list.get(i)); addView(tv, pa); ((ViewGroup.MarginLayoutParams) tv.getLayoutParams()).setMargins(DensityUtils.dp2px(getContext(), 5), DensityUtils.dp2px(getContext(), 5), DensityUtils.dp2px(getContext(), 5), DensityUtils.dp2px(getContext(), 5)); tv.setBackgroundResource(R.drawable.flag_01); }}Copy the code

Add click events

public interface IOnTabClickListener { void onTabClick(int position, TextView textView); } private void setOnclick(final int position, final TextView textView) { textView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { iOnTabClickListener.onTabClick(position, textView); }}); }Copy the code
Afterword.

The e harder part to understand is onMeasure. Find the maximum width value when setting wrap. And set the coordinates of each view.