网上很多类似adapter形式的添加标签的流式布局,由于新的需求,没有必要那么麻烦,所以就自己定义了简单展示的流式布局的样式。
内部元素可以根据自己的条件来隐藏展示gone或visible,达到动态展示多少的效果。仅作参考。复杂的还是使用adapter形式的流式布局展示。
先上代码:
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
import cn.gome.staff.buss.guide.R;
public class FlexboxLayout extends LinearLayout {
public FlexboxLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
resolveAttrs(context, attrs);
}
public FlexboxLayout(Context context, AttributeSet attrs) {
super(context, attrs);
resolveAttrs(context, attrs);
}
public FlexboxLayout(Context context) {
super(context);
resolveAttrs(context, null);
}
private void resolveAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlexboxLayout);
int lineAlignment = a.getInt(R.styleable.FlexboxLayout_lineAlignment, 0);
switch (lineAlignment) {
case 0:
mLineAlignment = FlexAlign.TopTop;
break;
case 1:
mLineAlignment = FlexAlign.TopCenter;
break;
case 2:
mLineAlignment = FlexAlign.TopBottom;
break;
case 3:
mLineAlignment = FlexAlign.CenterTop;
break;
case 4:
mLineAlignment = FlexAlign.CenterCenter;
break;
case 5:
mLineAlignment = FlexAlign.CenterBottom;
break;
case 6:
mLineAlignment = FlexAlign.BottomTop;
break;
case 7:
mLineAlignment = FlexAlign.BottomCenter;
break;
case 8:
mLineAlignment = FlexAlign.BottomBottom;
break;
}
mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlexboxLayout_horizontalSpacing, 0);
mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlexboxLayout_verticalSpacing, 0);
a.recycle();
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
private FlexAlign mLineAlignment;
private int mHorizontalSpacing;
private int mVerticalSpacing;
public FlexAlign getLineAlignment() {
return mLineAlignment;
}
public void setLineAlignment(FlexAlign alignment) {
mLineAlignment = alignment;
}
public int getHorizontalSpacing() {
return mHorizontalSpacing;
}
public void setHorizontalSpacing(int spacing) {
if (spacing >= 0)
mHorizontalSpacing = spacing;
}
public int getVerticalSpacing() {
return mVerticalSpacing;
}
public void setVerticalSpacing(int spacing) {
if (spacing >= 0)
mVerticalSpacing = spacing;
}
private int computeWidth(List widths) {
int maxWidth = 0;
for (Integer width : widths) {
maxWidth = Math.max(maxWidth, width);
}
return maxWidth + getPaddingLeft() + getPaddingRight();
}
private int computeHeight(List heights) {
int heightSum = 0;
for (Integer height : heights) {
heightSum += height;
}
int lineCount = heights.size();
if (lineCount > 1) {
heightSum += (lineCount - 1) * mVerticalSpacing;
}
return heightSum + getPaddingTop() + getPaddingBottom();
}
private List getVisibleChildViews() {
List visibleChildViews = new ArrayList<>();
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
int childViewVisibility = childView.getVisibility();
if (childViewVisibility != View.GONE) {
visibleChildViews.add(childView);
}
}
return visibleChildViews;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
List widths = new ArrayList<>();
List heights = new ArrayList<>();
int lineWidth = 0;
int lineHeight = 0;
List visibleChildViews = getVisibleChildViews();
int visibleChildViewCount = visibleChildViews.size();
for (int i = 0; i < visibleChildViewCount; i++) {
View visibleChildView = visibleChildViews.get(i);
measureChild(visibleChildView, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams mlp = (MarginLayoutParams) visibleChildView.getLayoutParams();
int childWidth = visibleChildView.getMeasuredWidth() + mlp.leftMargin + mlp.rightMargin;
int childHeight = visibleChildView.getMeasuredHeight() + mlp.topMargin + mlp.bottomMargin;
if (i == 0) {
lineWidth = childWidth;
lineHeight = childHeight;
} else {
if (lineWidth + mHorizontalSpacing + childWidth <= widthSize - paddingLeft - paddingRight) {
lineWidth += mHorizontalSpacing + childWidth;
lineHeight = Math.max(lineHeight, childHeight);
} else {
widths.add(lineWidth);
heights.add(lineHeight);
lineWidth = childWidth;
lineHeight = childHeight;
}
}
if (i == visibleChildViewCount - 1) {
widths.add(lineWidth);
heights.add(lineHeight);
}
}
int computedWidth = computeWidth(widths);
int computedHeight = computeHeight(heights);
int measuredWidth = 0;
int measuredHeight = 0;
int minWidth = getSuggestedMinimumWidth();
int minHeight = getSuggestedMinimumHeight();
switch (widthMode) {
case MeasureSpec.EXACTLY:
measuredWidth = widthSize;
break;
case MeasureSpec.AT_MOST:
measuredWidth = Math.max(computedWidth, minWidth);
measuredWidth = Math.min(widthSize, measuredWidth);
break;
case MeasureSpec.UNSPECIFIED:
measuredWidth = Math.max(computedWidth, minWidth);
break;
}
switch (heightMode) {
case MeasureSpec.EXACTLY:
measuredHeight = heightSize;
break;
case MeasureSpec.AT_MOST:
measuredHeight = Math.max(computedHeight, minHeight);
measuredHeight = Math.min(heightSize, measuredHeight);
break;
case MeasureSpec.UNSPECIFIED:
measuredHeight = Math.max(computedHeight, minHeight);
break;
}
setMeasuredDimension(measuredWidth, measuredHeight);
}
private void layoutLineViews(List lineViews, int lineLeft, int lineTop, int lineWidth, int lineHeight) {
for (View view : lineViews) {
MarginLayoutParams viewMLP = (MarginLayoutParams) view.getLayoutParams();
int viewW = view.getMeasuredWidth() + viewMLP.leftMargin + viewMLP.rightMargin;
int viewH = view.getMeasuredHeight() + viewMLP.topMargin + viewMLP.bottomMargin;
int viewL = lineLeft + viewMLP.leftMargin;
int viewT = mLineAlignment.getY(lineTop, lineHeight, viewH) + viewMLP.topMargin;
int viewR = viewL + view.getMeasuredWidth();
int viewB = viewT + view.getMeasuredHeight();
view.layout(viewL, viewT, viewR, viewB);
lineLeft += viewW + mHorizontalSpacing;
}
lineViews.clear();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int w = r - l;
int h = b - t;
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int lineLeft = 0;
int lineTop = 0;
int lineWidth = 0;
int lineHeight = 0;
List lineViews = new ArrayList<>();
List visibleChildViews = getVisibleChildViews();
int visibleChildViewCount = visibleChildViews.size();
for (int i = 0; i < visibleChildViewCount; i++) {
View visibleChildView = visibleChildViews.get(i);
MarginLayoutParams mlp = (MarginLayoutParams) visibleChildView.getLayoutParams();
int childWidth = visibleChildView.getMeasuredWidth() + mlp.leftMargin + mlp.rightMargin;
int childHeight = visibleChildView.getMeasuredHeight() + mlp.topMargin + mlp.bottomMargin;
if (i == 0) {
lineLeft = paddingLeft;
lineTop = paddingTop;
lineWidth = childWidth;
lineHeight = childHeight;
lineViews.add(visibleChildView);
} else {
if (lineWidth + mHorizontalSpacing + childWidth <= w - paddingLeft - paddingRight) {
lineWidth += mHorizontalSpacing + childWidth;
lineHeight = Math.max(lineHeight, childHeight);
lineViews.add(visibleChildView);
} else {
layoutLineViews(lineViews, lineLeft, lineTop, lineWidth, lineHeight);
lineLeft = paddingLeft;
lineTop += lineHeight + mVerticalSpacing;
lineWidth = childWidth;
lineHeight = childHeight;
lineViews.add(visibleChildView);
}
}
if (i == visibleChildViewCount - 1) {
layoutLineViews(lineViews, lineLeft, lineTop, lineWidth, lineHeight);
}
}
}
private boolean mSuperHandledTouchEvent;
private boolean onSuperTouchEvent(MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
mSuperHandledTouchEvent = super.onTouchEvent(event);
} else {
if (mSuperHandledTouchEvent) {
mSuperHandledTouchEvent = super.onTouchEvent(event);
}
}
return mSuperHandledTouchEvent;
}
}
引用的一个类:
public enum FlexAlign {
TopTop,
TopCenter,
TopBottom,
CenterTop,
CenterCenter,
CenterBottom,
BottomTop,
BottomCenter,
BottomBottom;
public int getY(int baseY, int baseHeight, int height) {
switch (this) {
case TopTop:
return baseY;
case TopCenter:
return baseY - height / 2;
case TopBottom:
return baseY - height;
case CenterTop:
return baseY + baseHeight / 2;
case CenterCenter:
return baseY + (baseHeight - height) / 2;
case CenterBottom:
return baseY + baseHeight / 2 - height;
case BottomTop:
return baseY + baseHeight;
case BottomCenter:
return baseY + baseHeight - height / 2;
case BottomBottom:
return baseY + baseHeight - height;
default:
return baseY + (baseHeight - height) / 2;
}
}
public float getY(float baseY, float baseHeight, float height) {
switch (this) {
case TopTop:
return baseY;
case TopCenter:
return baseY - height / 2;
case TopBottom:
return baseY - height;
case CenterTop:
return baseY + baseHeight / 2;
case CenterCenter:
return baseY + (baseHeight - height) / 2;
case CenterBottom:
return baseY + baseHeight / 2 - height;
case BottomTop:
return baseY + baseHeight;
case BottomCenter:
return baseY + baseHeight - height / 2;
case BottomBottom:
return baseY + baseHeight - height;
default:
return baseY + (baseHeight - height) / 2;
}
}
}
values里面的attrs.xml属性
引入方法很简单,直接在xml里面引入