dzwillpower
5/20/2016 - 6:42 AM

Android FlowLayout demo.

Android FlowLayout demo.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">FlowLayout</string>
</resources>
<resources>
  <dimen name="flowlayout_horizontal_padding">10dp</dimen>
  <dimen name="flowlayout_vertical_padding">10dp</dimen>
</resources>
<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/container"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <hzqtc.flowlayout.FlowLayout
      android:id="@+id/flow_container"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:padding="20dp"/>
  </ScrollView>
</FrameLayout>
package hzqtc.flowlayout;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;

import java.util.Locale;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ViewGroup flowContainer = (ViewGroup) findViewById(R.id.flow_container);
    for (Locale locale : Locale.getAvailableLocales()) {
      String countryName = locale.getDisplayCountry();
      if (!countryName.isEmpty()) {
        flowContainer.addView(createDummyTextView(countryName),
            new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
      }
    }
  }

  private View createDummyTextView(String text) {
    TextView textView = new TextView(this);
    textView.setText(text);
    return textView;
  }
}
package hzqtc.flowlayout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class FlowLayout extends ViewGroup {

  private int paddingHorizontal;
  private int paddingVertical;

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

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

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

  private void init() {
    paddingHorizontal = getResources().getDimensionPixelSize(R.dimen.flowlayout_horizontal_padding);
    paddingVertical = getResources().getDimensionPixelSize(R.dimen.flowlayout_vertical_padding);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int childLeft = getPaddingLeft();
    int childTop = getPaddingTop();
    int lineHeight = 0;
    // 100 is a dummy number, widthMeasureSpec should always be EXACTLY for FlowLayout
    int myWidth = resolveSize(100, widthMeasureSpec);
    int wantedHeight = 0;
    for (int i = 0; i < getChildCount(); i++) {
      final View child = getChildAt(i);
      if (child.getVisibility() == View.GONE) {
        continue;
      }
      // let the child measure itself
      child.measure(
          getChildMeasureSpec(widthMeasureSpec, 0, child.getLayoutParams().width),
          getChildMeasureSpec(heightMeasureSpec, 0, child.getLayoutParams().height));
      int childWidth = child.getMeasuredWidth();
      int childHeight = child.getMeasuredHeight();
      // lineheight is the height of current line, should be the height of the heightest view
      lineHeight = Math.max(childHeight, lineHeight);
      if (childWidth + childLeft + getPaddingRight() > myWidth) {
        // wrap this line
        childLeft = getPaddingLeft();
        childTop += paddingVertical + lineHeight;
        lineHeight = childHeight;
      }
      childLeft += childWidth + paddingHorizontal;
    }
    wantedHeight += childTop + lineHeight + getPaddingBottom();
    setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec));
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    int childLeft = getPaddingLeft();
    int childTop = getPaddingTop();
    int lineHeight = 0;
    int myWidth = right - left;
    for (int i = 0; i < getChildCount(); i++) {
      final View child = getChildAt(i);
      if (child.getVisibility() == View.GONE) {
        continue;
      }
      int childWidth = child.getMeasuredWidth();
      int childHeight = child.getMeasuredHeight();
      lineHeight = Math.max(childHeight, lineHeight);
      if (childWidth + childLeft + getPaddingRight() > myWidth) {
        childLeft = getPaddingLeft();
        childTop += paddingVertical + lineHeight;
        lineHeight = childHeight;
      }
      child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
      childLeft += childWidth + paddingHorizontal;
    }
  }
}
<?xml version="1.0" encoding="utf-8"?>
<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  package="hzqtc.flowlayout"
  android:versionCode="1"
  android:versionName="1.0">

  <uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="19"/>

  <application
    android:allowBackup="true"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.Holo.Light.DarkActionBar">
    <activity
      android:name="hzqtc.flowlayout.MainActivity"
      android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>
  </application>

</manifest>