原创博客,如有转载,请注明出处,非常感谢。
img1.png
如上图,view的自动换行,貌似现在很多app都很流行这个设计。
下面介绍两种实现方式:
一. 自定义控件WordWrapView
1. 在attrs.xml中定义控件需要的属性
<declare-styleable name="WordWrapView">
<attr name="spacing_vertical" format="dimension" />
<attr name="spacing_horizontal" format="dimension" />
</declare-styleable>
2.继承ViewGroup开始自定义控件。(逻辑非常简单,直接贴代码,不解释了...)
/**
* 自动换行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();// 横坐标开始
int y = 0;//纵坐标开始
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;//横坐标
int y = 0;//纵坐标
int rows = 1;//总行数
int specWidth = MeasureSpec.getSize(widthMeasureSpec);
int actualWidth = specWidth - getPaddingLeft() - getPaddingRight();//实际宽度
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. 使用
直接一个布局搞定。当然,如果里面的子item如果是动态的,可以使用viewGroup的addView()方法实现。
img2.png
img3.png
二. FlexboxLayout实现
FlexboxLayout是谷歌的一个开源项目,可以实现各种复杂布局。
FlexboxLayout开源地址:
https://github.com/google/flexbox-layout
1. 添加依赖
dependencies {
compile 'com.google.android:flexbox:0.3.0'
}
2. 使用
FlexboxLayout有一个属性flexWrap,代表是否支持换行排列,有三个值:
nowrap :不换行
wrap:按正常方向换行
wrap-reverse:按反方向换行
我们用第二个“wrap”就行,接下来继续上代码。
img4.png
img6.png
img5.png
3. 最后
效果和自定义控件一模一样,实现更简单。
如果想了解更多FlexboxLayout使用方法,可以参考:
http://www.oschina.net/news/73442/google-flexbox-layout