/**
* 可以自适应字符串长度然后进行的换行布局
* author: Jiang Boyan
* created at 2016/8/7
*/
public class WordWrapView extends ViewGroup {
private static final int PADDING_HOR = 18;//水平方向padding
private static final int PADDING_VERTICAL = 12;//垂直方向padding
private static final int SIDE_MARGIN = 12;//左右间距
private static final int TEXT_MARGIN = 12;
/**
* @param context
*/
public WordWrapView(Context context) {
super(context);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public WordWrapView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* @param context
* @param attrs
*/
public WordWrapView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int autualWidth = r - l;
int x = SIDE_MARGIN;// 横坐标开始
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 + TEXT_MARGIN;
if (x > autualWidth) {
x = width + SIDE_MARGIN;
rows++;
}
y = rows * (height + TEXT_MARGIN);
if (i == 0) {
view.layout(x - width - TEXT_MARGIN, y - height, x - TEXT_MARGIN, y);
} else {
view.layout(x - width, y - height, x, y);
}
}
}
@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 - SIDE_MARGIN * 2;//实际宽度
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
View child = getChildAt(index);
child.setPadding(PADDING_HOR, PADDING_VERTICAL, PADDING_HOR, PADDING_VERTICAL);
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight();
x += width + TEXT_MARGIN;
if (x > actualWidth) {//换行
x = width;
rows++;
}
y = rows * (height + TEXT_MARGIN);
}
setMeasuredDimension(actualWidth, y);
}
}
这里有个地方要注意:1.measure 2.layout
在两个步骤中分别调用回调函数:1.onMeasure() 2.onLayout()
- onMeasure() 在这个函数中,ViewGroup会接受childView的请求的大小,然后通过childView的 measure(newWidthMeasureSpec, heightMeasureSpec)函数存储到childView中,以便childView的getMeasuredWidth() andgetMeasuredHeight() 的值可以被后续工作得到。
- onLayout() 在这个函数中,ViewGroup会拿到childView的getMeasuredWidth() andgetMeasuredHeight(),用来布局所有的childView。
- View.MeasureSpec 与 LayoutParams 这两个类,是ViewGroup与childView协商大小用的。其中,View.MeasureSpec是ViewGroup用来部署 childView用的, LayoutParams是childView告诉ViewGroup 我需要多大的地方。
- 在View 的onMeasure的最后要调用setMeasuredDimension()这个方法存储View的大小,这个方法决定了当前View的大小。
布局文件中直接引用就ok。
最后是在Activity(Fragment)文件中使用的代码:
for (int i = 0; i < 7; i++){
TextView tv = new TextView(this);
tv.setBackgroundResource(R.drawable.round_bg_little);
tv.setTextColor(Color.WHITE);
tv.setText(dataa[i]);
wordwrapview.addView(tv);
}
这里直接在wordwrapview添加View就可以了,然后子View的样式可以自己引用,也不多提了~
希望可以帮到你~
网友评论