自定义标签多选更改背景图片
来源:互联网 发布:玛祖铭立 知乎 编辑:程序博客网 时间:2024/06/14 13:17
最近在做项目时候遇到了标签布局问题,当时我首选的是用流式布局TagFlowLayout的控件,可是发现不能满足我项目的需求,于是翻看了一下网页写了一个用配合ChekBox来实现多选标签的布局,在这写出来,希望对其他伙伴们有些帮助!
需取效果:
首先:我们需要一个实体类TagBean,确保有id,和name(显示的内容)
public class TagBean { private String id; private String name; public void setId(String id) { this.id = id; } public void setName(String name) { this.name = name; } public String getId() { return id; } public String getName() { return name; } public TagBean(String id, String name) { this.id = id; this.name = name; }}
然后就可以写我们的自定义布局了,重写ViewGroup,采用onDraw,onMeasure,onLayout等方法类似于流式布局,熟悉流式布局的小伙伴应该so easy,这里就不说太多了,直接上代码:
public class LabelLayout extends ViewGroup { private int mMaxCheckCount = Integer.MAX_VALUE; /** * 竖直方向间距, default is 8.0dp. */ private int horizontalSpacing; /** * 水平方向间距, default is 4.0dp. */ private int verticalSpacing; //whether or not to draw the divider between labels at horizon. private boolean enableDivider = false; //是否允许显示分割线 默认不显示 private int dividerColor = 0xffECECEC; private float dividerHeight; private int checkboxLayoutId; //nark checked labels. private Map<String, Boolean> labelcheckMap; //mark the first position in a row. private Set<Integer> rowPositons = new HashSet<>(); //The paint to draw the divider. Paint dividerPaint; public LabelLayout(Context context) { this(context, null); } public LabelLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LabelLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setWillNotDraw(false); labelcheckMap = new HashMap<>(); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LabelLayout, defStyleAttr, R.style.LabelLayoutDefault); try { horizontalSpacing = (int) a.getDimension(R.styleable.LabelLayout_label_horizontalSpacing, dp2px(8.0f)); verticalSpacing = (int) a.getDimension(R.styleable.LabelLayout_label_verticalSpacing, dp2px(4.0f)); checkboxLayoutId = a.getResourceId(R.styleable.LabelLayout_label_checkboxLayout, R.layout.view_label_common); enableDivider = a.getBoolean(R.styleable.LabelLayout_label_enableDivider, false); dividerHeight = a.getDimension(R.styleable.LabelLayout_label_dividerHeight, dp2px(2)); dividerColor = a.getColor(R.styleable.LabelLayout_label_dividerColor, 0xffECECEC); } finally { a.recycle(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (enableDivider) { if (dividerPaint == null) { dividerPaint = new Paint(); dividerPaint.setAntiAlias(true); dividerPaint.setColor(dividerColor); dividerPaint.setStyle(Paint.Style.FILL); } for (Integer top : rowPositons) { if (top != 0) { //draw lines between labels. canvas.drawRect(0, top - dividerHeight / 2, getMeasuredWidth(), top + dividerHeight / 2, dividerPaint); } } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec); final int widthSize = MeasureSpec.getSize(widthMeasureSpec); final int heightSize = MeasureSpec.getSize(heightMeasureSpec); measureChildren(widthMeasureSpec, heightMeasureSpec); int width = 0; int height = 0; int row = 0; // The row counter. int rowWidth = 0; // Calc the current row width. int rowMaxHeight = 0; // Calc the max tag height, in current row. final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); final int childWidth = child.getMeasuredWidth(); final int childHeight = child.getMeasuredHeight(); if (child.getVisibility() != GONE) { rowWidth += childWidth; if (rowWidth > widthSize) { // Next line. rowWidth = childWidth; // The next row width. height += rowMaxHeight + verticalSpacing; rowMaxHeight = childHeight; // The next row max height. row++; } else { // This line. rowMaxHeight = Math.max(rowMaxHeight, childHeight); } rowWidth += horizontalSpacing; }// System.out.println("measured height:" + height); rowPositons.add(height - verticalSpacing / 2); } // Account for the last row height. height += rowMaxHeight; // Account for the padding too. height += getPaddingTop() + getPaddingBottom(); // If the tags grouped in one row, set the width to wrap the tags. if (row == 0) { width = rowWidth; width += getPaddingLeft() + getPaddingRight(); } else {// If the tags grouped exceed one line, set the width to match the parent. width = widthSize; } setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width, heightMode == MeasureSpec.EXACTLY ? heightSize : height); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int parentLeft = getPaddingLeft(); final int parentRight = r - l - getPaddingRight(); final int parentTop = getPaddingTop(); final int parentBottom = b - t - getPaddingBottom(); int childLeft = parentLeft; int childTop = parentTop; int rowMaxHeight = 0; final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); final int width = child.getMeasuredWidth(); final int height = child.getMeasuredHeight(); if (child.getVisibility() != GONE) { if (childLeft + width > parentRight) { // Next line childLeft = parentLeft; childTop += rowMaxHeight + verticalSpacing; rowMaxHeight = height; } else { rowMaxHeight = Math.max(rowMaxHeight, height); } child.layout(childLeft, childTop, childLeft + width, childTop + height); childLeft += width + horizontalSpacing; } } } /** * set the default labels that you wanna to add into LabelLayout. * * @param labels A collection contains objects that implement ILabel interface. */ public void setLabels(List<TagBean> labels) { labelcheckMap.clear(); removeAllViews(); if (labels == null || labels.size() == 0) return; for (final TagBean label : labels) { final CheckBox tagView = (CheckBox) View.inflate(getContext(), checkboxLayoutId, null); tagView.setText(label.getName()); addView(tagView); tagView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) {//选中时添加到map if (labelcheckMap.size() > mMaxCheckCount - 1) { if (checkListener != null) { checkListener.onBeyondMaxCheckCount(); } tagView.setChecked(false); } else { labelcheckMap.put(label.getId(), true); if (checkListener != null) { checkListener.onCheckChanged(label, true); Drawable drawable = getResources().getDrawable(R.mipmap.select_tag); tagView.setCompoundDrawablePadding(10); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); //设置选中头部图片 tagView.setCompoundDrawables(drawable, null, null, null); } } } else {//否则及时清理map if (labelcheckMap.containsKey(label.getId())) { labelcheckMap.remove(label.getId()); if (checkListener != null) { checkListener.onCheckChanged(label, false); //设置未选中头部图片 tagView.setCompoundDrawables(null, null, null, null); } } } } }); } } /** * set the maximum numbers of checked labels. */ public void setMaxCheckCount(int count) { mMaxCheckCount = count; } /** * Get the current selected tag number. */ public int getCheckedLabelsCount() { int count = 0; for (Map.Entry<String, Boolean> m : labelcheckMap.entrySet()) { if (m.getValue()) { count++; } } return count; } public List<String> getCheckedLabelIds() { List<String> chechedLabelIds = new ArrayList<>(); for (Map.Entry<String, Boolean> m : labelcheckMap.entrySet()) { if (m.getValue()) { chechedLabelIds.add(m.getKey()); } } return chechedLabelIds; } /** * To serialize checked-label ids as json, make benefit for use. * * @return json string */ public String getCheckedIdsAsJson() { List<String> chechedId = new ArrayList<>(); for (Map.Entry<String, Boolean> m : labelcheckMap.entrySet()) { if (m.getValue()) { chechedId.add(m.getKey()); } } return new JSONArray(chechedId).toString(); } private float dp2px(float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } //监听方法 private OnCheckChangeListener checkListener; public interface OnCheckChangeListener { void onCheckChanged(TagBean label, boolean isChecked); void onBeyondMaxCheckCount(); } public void setOnCheckChangedListener(OnCheckChangeListener checkListener) { this.checkListener = checkListener; }
上面是布局类代码我全展示出来,
还有就是xml文件的代码:
ChekBox的:
<?xml version="1.0" encoding="utf-8"?><CheckBox xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="32dp" android:layout_margin="10dp" android:background="@drawable/label_selector" android:button="@null" android:paddingBottom="4dp" android:paddingLeft="13dp" android:paddingRight="13dp" android:paddingTop="4dp" android:text="hello" android:textColor="@drawable/label_gray_selector" android:textSize="16sp" />
背景选中效果代码:
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true"> <shape android:shape="rectangle"> <corners android:radius="6dp" /> <solid android:color="#fff" /> </shape> </item> <item> <shape android:shape="rectangle"> <corners android:radius="6dp" /> <stroke android:width="1dp" android:color="#fff" /> </shape> </item></selector>
字体选中效果:
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="#FF9400" android:state_checked="true" /> <item android:color="#434343" /></selector>
主布局 :
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.l.tag_label.MainActivity"> <com.example.l.tag_label.LabelLayout android:id="@+id/label_me" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" > </com.example.l.tag_label.LabelLayout> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="bt" android:text="点击"/></LinearLayout>
然后就是activity中的代码了,
首先添加数据:
private ArrayList<TagBean> initList() { ArrayList<TagBean> list = new ArrayList<>(); for (int i = 0; i < 8; i++) { TagBean bean = new TagBean(i + "", "hello" + i); list.add(bean); } return list; }
然后再把数据传过去,
tab.setLabels(list);// 设置数据 tab.setMaxCheckCount(4);// 设置最大选中数量 // 点击选中取消监听 tab.setOnCheckChangedListener(new LabelLayout.OnCheckChangeListener() { @Override public void onCheckChanged(TagBean label, boolean isChecked) { String name = label.getName(); Toast.makeText(MainActivity.this, isChecked + "==" + name, Toast.LENGTH_SHORT).show(); Log.d("dd", name + ""); // 在这块可以自己写个集合储存一下 if (isChecked) name_liat.add(name); else name_liat.remove(name); } @Override public void onBeyondMaxCheckCount() { } });
最后执行自己的button按钮监听方法就可以把集合里面的东西拿出来了。
public void bt(View view) { for (int i = 0; i <name_liat.size() ; i++) { Log.d("ee", name_liat.get(i).toString() + ""); } }
写的够详细,简单了!如果感觉有帮助,请点赞!!^_^
效果图:
阅读全文
0 0
- 自定义标签多选更改背景图片
- grub2更改背景图片
- 更改SAP的背景图片
- 更改NavigationController的背景图片
- css更改背景图片大小
- 如何更改背景图片透明度
- 去掉UISearchBar背景图片,自定义背景图片
- tlds自定义标签可以使用uri配置来更改引用
- 动态更改水晶报表背景图片
- 更改Ubuntu 的登录背景图片
- ListView 的Item更改背景图片
- C# 动态更改imagebox背景图片
- button设置点击更改背景图片
- IDEA如何设置更改背景图片
- 自定义navigationbar背景图片
- 自定义UITabBar 背景图片
- 自定义UINavigationBar的背景图片
- IOS 自定义 UIDatePicker 背景图片
- curl的优势
- 用windows cmd编译c++程序及其他
- HDU 2612
- 剑指offer——31.整数中1出现的次数
- 悲观锁和乐观锁
- 自定义标签多选更改背景图片
- LeetCode 27. Remove Element
- C# 窗口间的通讯
- IP地址为140.123.0.0的地址是B类地址,若要切割为10个子网,而且都要连接上Internet,请问子网掩码应设为
- Docker+Gogs搭建个人Git服务
- python爬虫练习4:刷博客浏览量
- 黑盒测试、白盒测试、灰盒测试之间区别
- Redis PFADD
- 管道