根究标签的字数长短,动态控制每行显示的item个数,我们通过自定义View来实现,下面是效果图:
代码实现:
1、自定义View
public class LineBreakLayout extends ViewGroup {
private final static String TAG = "LineBreakLayout";
/**
* 所有标签
*/
private List<String> lables;
/**
* 选中标签
*/
private List<String> lableSelected = new ArrayList<>();
//自定义属性
private int LEFT_RIGHT_SPACE; //dip
private int ROW_SPACE;
public LineBreakLayout(Context context) {
this(context, null);
}
public LineBreakLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LineBreakLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LineBreakLayout);
LEFT_RIGHT_SPACE = ta.getDimensionPixelSize(R.styleable.LineBreakLayout_leftAndRightSpace, 10);
ROW_SPACE = ta.getDimensionPixelSize(R.styleable.LineBreakLayout_rowSpace, 10);
ta.recycle(); //回收
// ROW_SPACE=20 LEFT_RIGHT_SPACE=40
Log.v(TAG, "ROW_SPACE="+ROW_SPACE+" LEFT_RIGHT_SPACE="+LEFT_RIGHT_SPACE);
}
/**
* 添加标签
* @param lables 标签集合
* @param add 是否追加
*/
public void setLables(List<String> lables, boolean add){
if(this.lables == null){
this.lables = new ArrayList<>();
}
if(add){
this.lables.addAll(lables);
}else{
this.lables.clear();
this.lables = lables;
}
if(lables!=null && lables.size()>0){
LayoutInflater inflater = LayoutInflater.from(getContext());
for (final String lable : lables) {
//获取标签布局
final TextView tv = (TextView) inflater.inflate(R.layout.item_lable, null);
tv.setText(lable);
//设置选中效果
if (lableSelected.contains(lable)) {
//选中
tv.setSelected(true);
tv.setTextColor(getResources().getColor(R.color.tv_blue));
} else {
//未选中
tv.setSelected(false);
tv.setTextColor(getResources().getColor(R.color.tv_gray));
}
//点击标签后,重置选中效果
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv.setSelected(tv.isSelected() ? false : true);
if (tv.isSelected()) {
tv.setTextColor(getResources().getColor(R.color.tv_blue));
//将选中的标签加入到lableSelected中
lableSelected.add(lable);
} else {
tv.setTextColor(getResources().getColor(R.color.tv_gray));
lableSelected.remove(lable);
}
}
});
//将标签添加到容器中
addView(tv);
}
}
}
/**
* 获取选中标签
*/
public List<String> getSelectedLables(){
return lableSelected;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//为所有的标签childView计算宽和高
measureChildren(widthMeasureSpec, heightMeasureSpec);
//获取高的模式
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//建议的高度
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//布局的宽度采用建议宽度(match_parent或者size),如果设置wrap_content也是match_parent的效果
int width = MeasureSpec.getSize(widthMeasureSpec);
int height ;
if (heightMode == MeasureSpec.EXACTLY) {
//如果高度模式为EXACTLY(match_perent或者size),则使用建议高度
height = heightSize;
} else {
//其他情况下(AT_MOST、UNSPECIFIED)需要计算计算高度
int childCount = getChildCount();
if(childCount<=0){
height = 0; //没有标签时,高度为0
}else{
int row = 1; // 标签行数
int widthSpace = width;// 当前行右侧剩余的宽度
for(int i = 0;i<childCount; i++){
View view = getChildAt(i);
//获取标签宽度
int childW = view.getMeasuredWidth();
Log.v(TAG , "标签宽度:"+childW +" 行数:"+row+" 剩余宽度:"+widthSpace);
if(widthSpace >= childW ){
//如果剩余的宽度大于此标签的宽度,那就将此标签放到本行
widthSpace -= childW;
}else{
row ++; //增加一行
//如果剩余的宽度不能摆放此标签,那就将此标签放入一行
widthSpace = width-childW;
}
//减去标签左右间距
widthSpace -= LEFT_RIGHT_SPACE;
}
//由于每个标签的高度是相同的,所以直接获取第一个标签的高度即可
int childH = getChildAt(0).getMeasuredHeight();
//最终布局的高度=标签高度*行数+行距*(行数-1)
height = (childH * row) + ROW_SPACE * (row-1);
Log.v(TAG , "总高度:"+height +" 行数:"+row+" 标签高度:"+childH);
}
}
//设置测量宽度和测量高度
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int row = 0;
int right = 0; // 标签相对于布局的右侧位置
int botom; // 标签相对于布局的底部位置
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
int childW = childView.getMeasuredWidth();
int childH = childView.getMeasuredHeight();
//右侧位置=本行已经占有的位置+当前标签的宽度
right += childW;
//底部位置=已经摆放的行数*(标签高度+行距)+当前标签高度
botom = row * (childH + ROW_SPACE) + childH;
// 如果右侧位置已经超出布局右边缘,跳到下一行
// if it can't drawing on a same line , skip to next line
if (right > (r - LEFT_RIGHT_SPACE)){
row++;
right = childW;
botom = row * (childH + ROW_SPACE) + childH;
}
Log.d(TAG, "left = " + (right - childW) +" top = " + (botom - childH)+
" right = " + right + " botom = " + botom);
childView.layout(right - childW, botom - childH,right,botom);
right += LEFT_RIGHT_SPACE;
}
}
}
2、res-values下新建attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LineBreakLayout">
<!--标签之间左右距离-->
<attr name="leftAndRightSpace" format="dimension" />
<!--标签行距-->
<attr name="rowSpace" format="dimension" />
</declare-styleable>
</resources>
3、标签列表的item布局
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_item_lable_bg"
android:paddingBottom="5dip"
android:paddingLeft="12dip"
android:paddingRight="12dip"
android:paddingTop="5dip"
android:text="lable"
android:textSize="15sp"
android:textColor="@color/tv_gray" />
4、drawable
(1)shape_item_lable_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--选中效果-->
<item android:state_selected="true">
<shape >
<solid android:color="#ffffff" />
<stroke android:color="@color/tv_blue"
android:width="2px"/>
<corners android:radius="10000dip"/>
</shape>
</item>
<!--默认效果-->
<item>
<shape >
<solid android:color="#ffffff" />
<stroke android:color="@color/divider_gray"
android:width="2px"/>
<corners android:radius="10000dip"/>
</shape>
</item>
</selector>
5、color
<color name="tv_gray">#666666</color>
<color name="tv_blue">#308BE9</color>
<color name="divider_gray">#d9d9d9</color>
6、
public class LableListActivity extends Activity implements View.OnClickListener{
private LineBreakLayout lineBreakLayout;
private Button btnGetLabel;
private TextView tvShowLabel;
private List<String> selectedLables;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lable_list);
initView();
}
//初始化控件
private void initView() {
lineBreakLayout=findViewById(R.id.lineBreakLayout);
btnGetLabel= findViewById(R.id.btn_get_label);
tvShowLabel = findViewById(R.id.tv_show_label);
btnGetLabel.setOnClickListener(this);
initLael();
}
//初始化标签
private void initLael() {
List<String> lable = new ArrayList<>();
lable.add("经济");
lable.add( "娱乐");
lable.add("八卦");
lable.add("小道消息");
lable.add("政治中心");
lable.add("彩票");
lable.add("情感");
lable.add("天文爱好者");
lable.add("完美主义者阿了哈");
lable.add("人傻钱多");
lable.add("选择困难症");
lable.add("旅游爱好者");
//设置标签
lineBreakLayout.setLables(lable, true);
//获取选中的标签
selectedLables = lineBreakLayout.getSelectedLables();
}
//点击事件
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_get_label:
tvShowLabel.setText("选中的标签为:"+selectedLables.toString());
break;
}
}
}
7、
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:openXu="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context="com.jiyaruo.neighbour.circle.haveuse.lable.LableListActivity">
<com.jiyaruo.neighbour.circle.haveuse.lable.LineBreakLayout
android:id="@+id/lineBreakLayout"
android:layout_margin="20dp"
openXu:leftAndRightSpace="20dp"
openXu:rowSpace="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.jiyaruo.neighbour.circle.haveuse.lable.LineBreakLayout>
<Button
android:id="@+id/btn_get_label"
android:text="获取选中的标签"
android:layout_marginLeft="20dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_show_label"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:textColor="#6f6f6f"
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>