流式佈局之FlowLayout使用
阿新 • • 發佈:2018-12-10
package com.a520it.mygoogleplay.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public class FlowLayout extends ViewGroup
{
private List mLines = new ArrayList(); // 用來記錄描述有多少行View
private Line mCurrrenLine; // 用來記錄當前已經新增到了哪一行
private int mHorizontalSpace = 10;
private int mVerticalSpace = 10;
public FlowLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public FlowLayout(Context context) { super(context); // TODO Auto-generated constructor stub } public void setSpace(int horizontalSpace, int verticalSpace) { this.mHorizontalSpace = horizontalSpace; this.mVerticalSpace = verticalSpace; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 清空 mLines.clear(); mCurrrenLine = null; int layoutWidth = MeasureSpec.getSize(widthMeasureSpec); // 獲取行最大的寬度 int maxLineWidth = layoutWidth - getPaddingLeft() - getPaddingRight(); // 測量孩子 int count = getChildCount(); for (int i = 0; i < count; i++) { View view = getChildAt(i); // 如果孩子不可見 if (view.getVisibility() == View.GONE) { continue; } // 測量孩子 measureChild(view, widthMeasureSpec, heightMeasureSpec); // 往lines新增孩子 if (mCurrrenLine == null) { // 說明還沒有開始新增孩子 mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace); // 新增到 Lines中 mLines.add(mCurrrenLine); // 行中一個孩子都沒有 mCurrrenLine.addView(view); } else { // 行不為空,行中有孩子了 boolean canAdd = mCurrrenLine.canAdd(view); if (canAdd) { // 可以新增 mCurrrenLine.addView(view); } else { // 不可以新增,裝不下去 // 換行 // 新建行 mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace); // 新增到lines中 mLines.add(mCurrrenLine); // 將view新增到line mCurrrenLine.addView(view); } } } // 設定自己的寬度和高度 int measuredWidth = layoutWidth; // paddingTop + paddingBottom + 所有的行間距 + 所有的行的高度 float allHeight = 0; for (int i = 0; i < mLines.size(); i++) { float mHeigth = mLines.get(i).mHeigth; // 加行高 allHeight += mHeigth; // 加間距 if (i != 0) { allHeight += mVerticalSpace; } } int measuredHeight = (int) (allHeight + getPaddingTop() + getPaddingBottom() + 0.5f); setMeasuredDimension(measuredWidth, measuredHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 給Child 佈局---> 給Line佈局 int paddingLeft = getPaddingLeft(); int offsetTop = getPaddingTop(); for (int i = 0; i < mLines.size(); i++) { Line line = mLines.get(i); // 給行佈局 line.layout(paddingLeft, offsetTop); offsetTop += line.mHeigth + mVerticalSpace; } } class Line { // 屬性 private List<View> mViews = new ArrayList<View>(); // 用來記錄每一行有幾個View private float mMaxWidth; // 行最大的寬度 private float mUsedWidth; // 已經使用了多少寬度 private float mHeigth; // 行的高度 private float mMarginLeft; private float mMarginRight; private float mMarginTop; private float mMarginBottom; private float mHorizontalSpace; // View和view之間的水平間距 // 構造 public Line(int maxWidth, int horizontalSpace) { this.mMaxWidth = maxWidth; this.mHorizontalSpace = horizontalSpace; } // 方法 /** * 新增view,記錄屬性的變化 * * @param view */ public void addView(View view) { // 載入View的方法 int size = mViews.size(); int viewWidth = view.getMeasuredWidth(); int viewHeight = view.getMeasuredHeight(); // 計算寬和高 if (size == 0) { // 說還沒有新增View if (viewWidth > mMaxWidth) { mUsedWidth = mMaxWidth; } else { mUsedWidth = viewWidth; } mHeigth = viewHeight; } else { // 多個view的情況 mUsedWidth += viewWidth + mHorizontalSpace; mHeigth = mHeigth < viewHeight ? viewHeight : mHeigth; } // 將View記錄到集合中 mViews.add(view); } /** * 用來判斷是否可以將View新增到line中 * * @param view * @return */ public boolean canAdd(View view) { // 判斷是否能新增View int size = mViews.size(); if (size == 0) { return true; } int viewWidth = view.getMeasuredWidth(); // 預計使用的寬度 float planWidth = mUsedWidth + mHorizontalSpace + viewWidth; if (planWidth > mMaxWidth) { // 加不進去 return false; } return true; } /** * 給孩子佈局 * * @param offsetLeft * @param offsetTop */ public void layout(int offsetLeft, int offsetTop) { // 給孩子佈局 int currentLeft = offsetLeft; int size = mViews.size(); // 判斷已經使用的寬度是否小於最大的寬度 float extra = 0; float widthAvg = 0; if (mMaxWidth > mUsedWidth) { extra = mMaxWidth - mUsedWidth; widthAvg = extra / size; } for (int i = 0; i < size; i++) { View view = mViews.get(i); int viewWidth = view.getMeasuredWidth(); int viewHeight = view.getMeasuredHeight(); // 判斷是否有富餘 if (widthAvg != 0) { // 改變寬度 int newWidth = (int) (viewWidth + widthAvg + 0.5f); int widthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY); int heightMeasureSpec = MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY); view.measure(widthMeasureSpec, heightMeasureSpec); viewWidth = view.getMeasuredWidth(); viewHeight = view.getMeasuredHeight(); } // 佈局 int left = currentLeft; int top = (int) (offsetTop + (mHeigth - viewHeight) / 2 + 0.5f); // int top = offsetTop; int right = left + viewWidth; int bottom = top + viewHeight; view.layout(left, top, right, bottom); currentLeft += viewWidth + mHorizontalSpace; } } }
}