1. 程式人生 > >自定義標籤多選更改背景圖片

自定義標籤多選更改背景圖片

最近在做專案時候遇到了標籤佈局問題,當時我首選的是用流式佈局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() + "");
        }

    }

寫的夠詳細,簡單了!如果感覺有幫助,請點贊!!^_^
效果圖:這裡寫圖片描述
這裡寫圖片描述