android 动态布局标签每行标签居中显示
强大的FlexboxLayoutManager
1 RecyclerView配合FlexboxLayoutManager无比强大,你想要的效果都能实现
2 缺点只需显示2行剩下显示不完的不再显示,不支持
3 修补2的问题
private final static int maxHeight = 130;
private View view;
public OnViewGlobalLayoutListener(View view) {
this.view = view;
}
@Override
public void onGlobalLayout() {
if (view.getHeight() > maxHeight)
view.getLayoutParams().height = maxHeight;
}
add listener to RecyclerView:
view.getViewTreeObserver()
.addOnGlobalLayoutListener(new OnViewGlobalLayoutListener(view));
### 简洁版
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import com.google.android.flexbox.FlexboxLayout;
public class FlowTagLayout extends FlexboxLayout {
/**
* Should be used by subclasses to listen to changes in the dataset
*/
AdapterDataSetObserver mDataSetObserver;
/**
* The adapter containing the data to be displayed by this view
*/
ListAdapter mAdapter;
/**
* the tag click event callback
*/
OnTagClickListener mOnTagClickListener;
public FlowTagLayout(Context context) {
super(context);
}
public FlowTagLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FlowTagLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// @Override
// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//
// int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
// int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
// int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
// int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
//
// //FlowLayout finally width and height
// int resultWidth = 0;
// int resultHeight = 0;
//
// int lineWidth = 0;
// int lineHeight = 0;
//
// for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
// View childView = getChildAt(i);
//
// measureChild(childView, widthMeasureSpec, heightMeasureSpec);
//
// int childWidth = childView.getMeasuredWidth();
// int childHeight = childView.getMeasuredHeight();
//
// MarginLayoutParams mlp = (MarginLayoutParams) childView.getLayoutParams();
// int realChildWidth = childWidth + mlp.leftMargin + mlp.rightMargin;
// int realChildHeight = childHeight + mlp.topMargin + mlp.bottomMargin;
//
// if ((lineWidth + realChildWidth) > sizeWidth) {
// //line feed
// resultWidth = Math.max(lineWidth, realChildWidth);
// resultHeight += realChildHeight;
// //after line feed,reset lineWidth and lineHeight
// lineWidth = realChildWidth;
// lineHeight = realChildHeight;
// } else {
// lineWidth += realChildWidth;
// lineHeight = Math.max(lineHeight, realChildHeight);
// }
//
// //遍历到最后一个的时候,肯定走的是不换行
// if (i == childCount - 1) {
// resultWidth = Math.max(lineWidth, resultWidth);
// resultHeight += lineHeight;
// }
//
// setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : resultWidth,
// modeHeight == MeasureSpec.EXACTLY ? sizeHeight : resultHeight);
//
// }
//
// }
//
// @Override
// protected void onLayout(boolean changed, int l, int t, int r, int b) {
//
// int flowWidth = getWidth();
//
// int childLeft = 0;
// int childTop = 0;
//
// for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
// View childView = getChildAt(i);
//
// //skip child view which set property to equal View.GONE
// if (childView.getVisibility() == View.GONE) {
// continue;
// }
//
// int childWidth = childView.getMeasuredWidth();
// int childHeight = childView.getMeasuredHeight();
//
// //child view maybe have margin
// MarginLayoutParams mlp = (MarginLayoutParams) childView.getLayoutParams();
//
// if (childLeft + mlp.leftMargin + childWidth + mlp.rightMargin > flowWidth) {
// //line feed
// childTop += (mlp.topMargin + childHeight + mlp.bottomMargin);
// childLeft = 0;
// }
// //layout
// int left = childLeft + mlp.leftMargin;
// int top = childTop + mlp.topMargin;
// int right = childLeft + mlp.leftMargin + childWidth;
// int bottom = childTop + mlp.topMargin + childHeight;
// childView.layout(left, top, right, bottom);
//
// childLeft += (mlp.leftMargin + childWidth + mlp.rightMargin);
// }
// }
//
// @Override
// public LayoutParams generateLayoutParams(AttributeSet attrs) {
// return new MarginLayoutParams(getContext(), attrs);
// }
public ListAdapter getAdapter() {
return mAdapter;
}
class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
super.onChanged();
reloadData();
}
@Override
public void onInvalidated() {
super.onInvalidated();
}
}
private void reloadData() {
removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
final int j = i;
final View childView = mAdapter.getView(i, null, this);
addView(childView, new MarginLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)));
childView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mOnTagClickListener != null) {
mOnTagClickListener.onItemClick(FlowTagLayout.this, childView, j);
}
}
});
}
}
public void setOnTagClickListener(OnTagClickListener onTagClickListener) {
this.mOnTagClickListener = onTagClickListener;
}
/**
* like ListView、GridView use FlowLayout
*
* @param adapter
*/
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
removeAllViews();
mAdapter = adapter;
if (mAdapter != null) {
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
}
}
public interface OnTagClickListener {
void onItemClick(FlowTagLayout parent, View view, int position);
}
}