public class TagLayout extends RelativeLayout {
}
private int mWidth;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w;
}
/**
* Adds a layout rule to be interpreted by the RelativeLayout. Use this for
* verbs that take a target, such as a sibling (ALIGN_RIGHT) or a boolean
* value (VISIBLE).
*
* @param verb One of the verbs defined by
* {@link android.widget.RelativeLayout RelativeLayout}, such as
* ALIGN_WITH_PARENT_LEFT.
* @param anchor The id of another view to use as an anchor,
* or a boolean value (represented as {@link RelativeLayout#TRUE}
* for true or 0 for false). For verbs that don't refer to another sibling
* (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
*/
public void addRule(int verb, int anchor) {
// ...
}
private void addTags() {
removeAllViews();
// 初始化各变量
int total = getPaddingLeft() + getPaddingRight();// 计算单行的宽度
int index = 1;// child的索引,同时也是child的viewId
int bottomAnchor = 1;// 添加到底部的child的id
int alignTopAnchor = 1;// 与之顶部对齐的child的id
for (String data : mData) {
// 初始化child视图
View child = mInflater.inflate(R.layout.tag, null);
// setId(index)这行代码很重要,将child的索引设为其id,在下面的代码中使用
child.setId(index);
TextView textView = (TextView) child.findViewById(R.id.text);
textView.setText(data);
// 测量child的宽度
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int childWidth = child.getMeasuredWidth();
// 为每一个child添加底部间距,这样就形成了行间距
LayoutParams childParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
childParams.bottomMargin = mChildBottomMargin;
// 如果单行已有的所有child宽度 + 本次需要添加的child的宽度和左间距 > 整个TagLayout的宽度
// 此时需要将child换行添加
if (total + mChildLeftMargin + childWidth > mWidth) {
// 设置LayoutParams:添加到viewId==bottomAnchor的child的底部
childParams.addRule(RelativeLayout.BELOW, bottomAnchor);
// total被重新初始化
total = getPaddingLeft() + getPaddingRight();
// 给bottomAnchor和alignTopAnchor赋值,后面会使用到
bottomAnchor = index;
alignTopAnchor = index;
} else {// 此时在同一行添加child
// 设置LayoutParams:与viewId==alignTopAnchor的child顶部对齐
childParams.addRule(RelativeLayout.ALIGN_TOP, alignTopAnchor);
// 如果该child不是本行的第一个
if (index != alignTopAnchor) {
// 设置LayoutParams:将child添加到前一个child的右侧
childParams.addRule(RelativeLayout.RIGHT_OF, index - 1);
// 设置LayoutParams:为child添加左边距,保持child之间的空隙
childParams.leftMargin = mChildLeftMargin;
// total累加child的左间距
total += mChildLeftMargin;
}
}
// 使用上面设置好的childParams,添加child
addView(child, childParams);
// total累加child的宽度
total += childWidth;
// index索引+1,进入下一轮循环
index++;
}
}
到这里,核心代码已经完成。再附上该控件的完整代码。
package net.csdn.blog.ruancoder;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.List;
public class TagLayout extends RelativeLayout {
private LayoutInflater mInflater;
private boolean mInited = false;
private int mWidth;
private int mChildLeftMargin;
private int mChildBottomMargin;
private List mData;
public TagLayout(Context context) {
super(context);
init(context);
}
public TagLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public TagLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mChildLeftMargin = context.getResources().getDimensionPixelSize(R.dimen.tag_leftmargin);
mChildBottomMargin = context.getResources().getDimensionPixelSize(R.dimen.tag_bottommargin);
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (!mInited) {
mInited = true;
addTags();
}
}
});
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w;
}
public void setData(List data) {
this.mData = data;
addTags();
}
private void addTags() {
if (!mInited) {
return;
}
if (mData == null || mData.isEmpty()) {
return;
}
removeAllViews();
int total = getPaddingLeft() + getPaddingRight();
int index = 1;
int bottomAnchor = 1;
int alignTopAnchor = 1;
for (String data : mData) {
View child = mInflater.inflate(R.layout.tag, null);
child.setId(index);
TextView textView = (TextView) child.findViewById(R.id.text);
textView.setText(data);
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int childWidth = child.getMeasuredWidth();
LayoutParams childParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
childParams.bottomMargin = mChildBottomMargin;
if (total + mChildLeftMargin + childWidth > mWidth) {
childParams.addRule(RelativeLayout.BELOW, bottomAnchor);
total = getPaddingLeft() + getPaddingRight();
bottomAnchor = index;
alignTopAnchor = index;
} else {
childParams.addRule(RelativeLayout.ALIGN_TOP, alignTopAnchor);
if (index != alignTopAnchor) {
childParams.addRule(RelativeLayout.RIGHT_OF, index - 1);
childParams.leftMargin = mChildLeftMargin;
total += mChildLeftMargin;
}
}
addView(child, childParams);
total += childWidth;
index++;
}
}
}