很多的搜索界面都會有這樣的布局:標(biāo)簽依次順序排列,當(dāng)一行放不下后自動(dòng)移動(dòng)到下一行晦毙,最近公司項(xiàng)目也要做一個(gè)這樣的效果来惧,網(wǎng)上搜了搜看到有很多類似的,但是因?yàn)楣镜囊茉O(shè)置間隔距離心例,所以決定自己寫一個(gè)宵凌,效果圖如下:
效果圖
AutoLinefeedLayout
public class AutoLinefeedLayout extends ViewGroup {
/**
* 子view左右間距
*/
private int mHorizontalSpacing;
/**
* 上下行距離
*/
private int mVerticalSpacing;
public AutoLinefeedLayout(Context context) {
this(context, null);
}
public AutoLinefeedLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoLinefeedLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (attrs != null) {
TypedArray array = context.obtainStyledAttributes(attrs,
R.styleable.AutoLayout);
mHorizontalSpacing = array.getDimensionPixelOffset(
R.styleable.AutoLayout_horizontalSpacing, 0);
mVerticalSpacing = array.getDimensionPixelOffset(
R.styleable.AutoLayout_verticalSpacing, 0);
array.recycle();
if (mHorizontalSpacing < 0) mHorizontalSpacing = 0;
if (mVerticalSpacing < 0) mVerticalSpacing = 0;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int count = getChildCount();
for (int i = 0; i < count; i++) {
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
}
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
getAutoLinefeedWidth(width), widthMode);
}
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
getAutoLinefeedHeight(width), heightMode);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 自動(dòng)換行 計(jì)算需要的寬度
*
* @param width 可用寬度
* @return 需要的寬度
*/
private int getAutoLinefeedWidth(int width) {
int totalWidth = getPaddingLeft() + getPaddingRight();
for (int i = 0; i < getChildCount(); i++) {
if (i > 0) totalWidth += mHorizontalSpacing;
View child = getChildAt(i);
int childWidth = child.getMeasuredWidth();
totalWidth += childWidth;
if (totalWidth >= width) {
totalWidth = width;
break;
}
}
return totalWidth;
}
/**
* 自動(dòng)換行 計(jì)算需要的高度
*
* @param width 可用寬度
* @return 需要的高度
*/
private int getAutoLinefeedHeight(int width) {
//一行最大可用寬度
int lineWidth = width - getPaddingLeft() - getPaddingRight();
//剩余可用寬度
int availableLineWidth = lineWidth;
//需要的高度
int totalHeight = getPaddingTop() + getPaddingBottom();
int lineChildIndex = 0;
//本行最大高度
int lineMaxHeight = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
//這個(gè)child需要的寬度 如果不是第一位的 那么需要加上間距
//這里是用來判斷需不需要換行
int needWidth = i == 0 ? childWidth : (childWidth + mHorizontalSpacing);
//如果剩余可用寬度小于需要的長度 那么換行
if (availableLineWidth < needWidth) {
totalHeight = totalHeight + lineMaxHeight;
if (i > 0) totalHeight += mVerticalSpacing;
availableLineWidth = lineWidth;
lineMaxHeight = 0;
lineChildIndex = 0;
}
//這個(gè)child需要的寬度 如果不是第一位的 那么需要加上間距
int realNeedWidth = lineChildIndex == 0 ? childWidth : (childWidth + mHorizontalSpacing);
lineMaxHeight = Math.max(childHeight, lineMaxHeight);
availableLineWidth = availableLineWidth - realNeedWidth;
lineChildIndex++;
}
totalHeight = totalHeight + lineMaxHeight;
return totalHeight;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
layout();
}
private void layout() {
int count = getChildCount();
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
int lineWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();
int availableLineWidth = lineWidth;
int lineChildIndex = 0;
//一行的最大高度
int lineMaxHeight = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int needWidth = i == 0 ? childWidth : (childWidth + mHorizontalSpacing);
if (availableLineWidth < needWidth) {
availableLineWidth = lineWidth;
childTop += lineMaxHeight;
if (i > 0) childTop += mVerticalSpacing;
lineMaxHeight = 0;
childLeft = getPaddingLeft();
lineChildIndex = 0;
}
int realNeedWidth = lineChildIndex == 0 ? childWidth : (childWidth + mHorizontalSpacing);
lineMaxHeight = Math.max(lineMaxHeight, childHeight);
child.layout(childLeft + realNeedWidth - childWidth, childTop, childLeft + realNeedWidth, childTop + childHeight);
availableLineWidth -= realNeedWidth;
childLeft += realNeedWidth;
lineChildIndex++;
}
}
public int getHorizontalSpacing() {
return mHorizontalSpacing;
}
public void setHorizontalSpacing(int horizontalSpacing) {
mHorizontalSpacing = horizontalSpacing;
}
public int getVerticalSpacing() {
return mVerticalSpacing;
}
public void setVerticalSpacing(int verticalSpacing) {
mVerticalSpacing = verticalSpacing;
}
}
attrs:
<declare-styleable name="AutoLinefeedLayout">
<attr name="horizontalSpacing" format="dimension"/>
<attr name="verticalSpacing" format="dimension"/>
</declare-styleable>
使用
activity中
AutoLinefeedLayout autoLinefeedLayout = findViewById(R.id.auto_linefeed_layout);
String[] labels = {"微信", "QQ", "網(wǎng)易云音樂", "支付寶", "UC瀏覽器", "鐵路12306", "釘釘", "攜程旅游", "手機(jī)淘寶", "58同城", "安居客", "滴滴出行"};
for (String label : labels) {
TextView textView = new TextView(getContext());
textView.setBackgroundColor(Color.BLACK);
textView.setTextColor(Color.WHITE);
textView.setText(label);
autoLinefeedLayout .addView(textView);
}
xml
<com.ph.test.test.weight.AutoLinefeedLayout
android:id="@+id/auto_linefeed_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:horizontalSpacing="10dp"
app:verticalSpacing="10dp"/>