原創(chuàng)博客,如有轉(zhuǎn)載,請注明出處,非常感謝。

img1.png
如上圖,view的自動(dòng)換行,貌似現(xiàn)在很多app都很流行這個(gè)設(shè)計(jì)。
下面介紹兩種實(shí)現(xiàn)方式:
一. 自定義控件WordWrapView
1. 在attrs.xml中定義控件需要的屬性
<declare-styleable name="WordWrapView">
<attr name="spacing_vertical" format="dimension" />
<attr name="spacing_horizontal" format="dimension" />
</declare-styleable>
2.繼承ViewGroup開始自定義控件。(邏輯非常簡單,直接貼代碼,不解釋了...)
/**
* 自動(dòng)換行view
* Created by ys on 2016/2/3.
*/
public class WordWrapView extends ViewGroup {
private float spacingVertical = 20;
private float spacingHorizontal = 20;
public WordWrapView(Context context) {
this(context, null);
}
public WordWrapView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WordWrapView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WordWrapView);
spacingHorizontal = a.getDimension(R.styleable.WordWrapView_spacing_horizontal, spacingHorizontal);
spacingVertical = a.getDimension(R.styleable.WordWrapView_spacing_vertical, spacingVertical);
a.recycle();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int autualWidth = r - l - getPaddingRight();
int x = getPaddingLeft();// 橫坐標(biāo)開始
int y = 0;//縱坐標(biāo)開始
int rows = 1;
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
x += width;
if (x > autualWidth) {
x = width + getPaddingLeft();
rows++;
}
y = rows * height + (rows - 1) * (int) spacingVertical + getPaddingTop();
view.layout(x - width, y - height, x, y);
x += spacingHorizontal;
}
}
;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int x = 0;//橫坐標(biāo)
int y = 0;//縱坐標(biāo)
int rows = 1;//總行數(shù)
int specWidth = MeasureSpec.getSize(widthMeasureSpec);
int actualWidth = specWidth - getPaddingLeft() - getPaddingRight();//實(shí)際寬度
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
View child = getChildAt(index);
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight();
x += width;
if (x > actualWidth) {//換行
x = width;
rows++;
}
x += spacingHorizontal;
y = rows * height + (rows - 1) * (int) spacingVertical + getPaddingTop() + getPaddingBottom();
}
setMeasuredDimension(specWidth, y);
}
}
3. 使用
直接一個(gè)布局搞定。當(dāng)然,如果里面的子item如果是動(dòng)態(tài)的,可以使用viewGroup的addView()方法實(shí)現(xiàn)。

img2.png

img3.png
二. FlexboxLayout實(shí)現(xiàn)
FlexboxLayout是谷歌的一個(gè)開源項(xiàng)目,可以實(shí)現(xiàn)各種復(fù)雜布局。
FlexboxLayout開源地址:
https://github.com/google/flexbox-layout
1. 添加依賴
dependencies {
compile 'com.google.android:flexbox:0.3.0'
}
2. 使用
FlexboxLayout有一個(gè)屬性flexWrap,代表是否支持換行排列,有三個(gè)值:
nowrap :不換行
wrap:按正常方向換行
wrap-reverse:按反方向換行
我們用第二個(gè)“wrap”就行,接下來繼續(xù)上代碼。

img4.png

img6.png

img5.png
3. 最后
效果和自定義控件一模一樣,實(shí)現(xiàn)更簡單。
如果想了解更多FlexboxLayout使用方法,可以參考:
http://www.oschina.net/news/73442/google-flexbox-layout