1. 程式人生 > >Android自定義CheckBox CheckGroup超好用

Android自定義CheckBox CheckGroup超好用

MaterialDialog 仿Android 5.0原生的AlertDialog樣式的對話方塊一文中以及詳細介紹了單選/多選對話方塊的用法,但是在現實開發中,我們可能需要在Activity上進行單選多選操作,於是就在MaterialDialog庫中進行了再次封裝,其中CheckBox和CheckGroup這兩個類是這次封裝的結果,接下來將詳細介紹這兩個類的用法。

首先,先看效果圖:這裡寫圖片描述

先看下佈局檔案

<?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" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<Button android:id="@+id/hit" android:layout_width="match_parent" android:layout_height="wrap_content"
android:onClick="onClick" android:text="提示對話方塊"/>
<Button android:id="@+id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="列表對話方塊"/> <Button android:id
="@+id/radio" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="單選對話方塊"/>
<Button android:id="@+id/check" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="多選對話方塊"/> <com.common.design.CheckGroup android:id="@+id/checkGroup" android:layout_width="match_parent" android:layout_height="wrap_content" app:shape="circle"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/look" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="檢視選擇結果"/> <TextView android:id="@+id/result" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@android:color/black"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:orientation="horizontal"> <com.common.design.CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" app:text="預設屬性"/> <com.common.design.CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" app:colorChecked="#00AA00" app:colorUnchecked="#AAAAAA" app:middlePadding="20dp" app:shape="square" app:text="自定義屬性" app:textColor="#0000FF" app:textSize="17sp"/> </LinearLayout> </LinearLayout>

CheckBox屬性介紹

<resources>
    <declare-styleable name="CheckBox">
        <attr name="text" format="reference|string"/><!--單選/多選旁邊的文字-->
        <attr name="textColor" format="color|reference"/><!--文字顏色-->
        <attr name="textSize" format="dimension|reference"/><!--文字大小-->
        <attr name="middlePadding" format="dimension|integer"/><!--單選/多選與文字之間的距離-->
        <attr name="duration" format="integer"/><!--動畫時長-->
        <attr name="strokeWidth" format="dimension"/><!--選中時,勾的寬度以及未選中時描邊的寬度-->
        <attr name="colorTick" format="color|reference"/><!--選中時勾的顏色-->
        <attr name="colorChecked" format="color|reference"/><!--選中時的背景色-->
        <attr name="colorUnchecked" format="color|reference"/><!--未選中時的背景色-->
        <attr name="colorUncheckedStroke" format="color|reference"/><!--未選中時,描邊的顏色-->
        <attr name="checkBoxWidth" format="dimension|integer"/><!--單選/多選框的寬度-->
        <attr name="checkBoxHeight" format="dimension|integer"/><!--單選/多選框的高度-->

        <attr name="shape" format="enum"><!--CheckView形狀-->
            <enum name="circle" value="0"/><!--圓形-->
            <enum name="square" value="1"/><!--正方形-->
        </attr>
    </declare-styleable>
</resources>

Activity程式碼

public class MainActivity extends AppCompatActivity {
    CheckGroup mCheckGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mCheckGroup = (CheckGroup) findViewById(R.id.checkGroup);
        OptionWrapper optionWrapper = new OptionWrapper();
        optionWrapper.setOptions("數學", "語文", "英語", "物理", "化學");
        optionWrapper.setChecked(1, 2, 4);
        mCheckGroup.setOptionWrapper(optionWrapper);
    }

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.look:
                List<CharSequence> checkedText = mCheckGroup.getCheckedText();
                StringBuilder builder = new StringBuilder();
                for (CharSequence charSequence : checkedText) {
                    builder.append(charSequence).append("、");
                }
                if (builder.length() > 0)
                    builder.deleteCharAt(builder.length() - 1);
                ((TextView) findViewById(R.id.result)).setText(builder);
                break;

            case R.id.hit:
                new MaterialDialog.Builder(this)
                        .setTitle("提示")
                        .setMessage("仿原生AlertDialog樣式的對話方塊,目的在於解決原生的在Android 5.0下樣式醜陋問題")
                        .setPositiveButton(new MaterialDialog.OnClickListener() {
                            @Override
                            public boolean onClick(DialogInterface dialog, int which) {
                                return false;
                            }
                        })
                        .setNeutralButton("不再提示", null)
                        .setNegativeButton(null).show();
                break;
            case R.id.list:
                final String[] items = {"2016/01", "2016/02", "2016/03", "2016/04", "2016/05", "2016/06", "2016/07"};
                new MaterialDialog.Builder(this)
                        .setItems(items, new MaterialDialog.OnClickListener() {
                            @Override
                            public boolean onClick(DialogInterface dialog, int which) {
                                Toast.makeText(MainActivity.this, items[which], Toast.LENGTH_SHORT).show();
                                return false;
                            }
                        }).create().show();
                break;
            case R.id.radio:
                final String[] item2 = {"2016/01", "2016/02", "2016/03", "2016/04", "2016/05", "2016/06", "2016/07"};
                new MaterialDialog.Builder(this)
                        .setTitle("單選框")
                        .setSingleChoiceItems(item2, 2, new MaterialDialog.OnClickListener() {
                            @Override
                            public boolean onClick(DialogInterface dialog, int which) {
                                Toast.makeText(MainActivity.this, item2[which], Toast.LENGTH_SHORT).show();
                                return true;
                            }
                        }).setPositiveButton("確定", null)
                        .setNegativeButton("取消", null)
                        .setNeutralButton("不在提示", null).show();
                break;
            case R.id.check:
                final String[] item1 = {"2016/01", "2016/02", "2016/03", "2016/04", "2016/05", "2016/06", "2016/07"};
                new MaterialDialog.Builder(this)
                        .setTitle("多選框")
                        .setMultiChoiceItems(item1, new int[]{1, 2, 3}, new MaterialDialog.OnMultiChoiceClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                                Toast.makeText(MainActivity.this, which + "--" + isChecked, Toast.LENGTH_SHORT).show();
                            }
                        })
                        .setMCResultButton(new MaterialDialog.OnMCResultListener() {
                            @Override
                            public boolean onClick(DialogInterface dialog, List<Integer> checkItems) {
                                return false;
                            }
                        })
                        .setNegativeButton("取消", null)
                        .setNeutralButton("不在提示", null).show();
                break;

        }
    }
}

可能有人會有疑問:單選/多選用原生的RadioButton、RadioGroup和CheckBox就可以實現,為什麼還要去寫這些呢?
我的回答是:原生的固然好用,但是自己寫的更好用,這個稍後會有介紹;而且原生的在Android 5.0以下手機上顯示是非常醜的,自己寫的則向下相容到Api 10,所以即使在低版本的手機顯示也是跟高版本的手機上顯示的是一樣的介面

在這,只講解CheckBox和CheckGroup兩個類的用法,具體實現請到我的github上下載原始碼閱讀,原始碼上都有註解,且通俗易懂

1、CheckBox
在上面的程式碼中已經有了詳細的用法,且大部分用法跟原生的RadioButton一致,例如:setChecked(Boolean),setOnCheckedChangeListener等方法都是一致的。
CheckBox的優勢在於提供了一系列自定義的屬性,例如:自定義形狀(方形還是圓形),自定義選中/未選中時的顏色,文字的大小,顏色等等都可以自定義,最主要的是樣式向下相容到Api 10
CheckBox基本上可以代替原生的RadioButton和CheckBox,如有發現某些功能不能替代,請聯絡我,我會加上這些功能。

2、CheckGroup
CheckGroup繼承於ListView,所以它其實就是一個ListView,通過列表去展示單選/多選列表

mCheckGroup = (CheckGroup) findViewById(R.id.checkGroup);
OptionWrapper optionWrapper = new OptionWrapper();//Option的封裝類
optionWrapper.setOptions("數學", "語文", "英語", "物理", "化學");
optionWrapper.setChecked(1, 2, 4);//預設選中position為1 2 4的選項
mCheckGroup.setShape(CheckGroup.SQUARE);//畫方形,圓形傳:CheckGroup.CIRCLE
mCheckGroup.setOptionWrapper(optionWrapper);

通過以上程式碼就可以在Activity上展示單選/多選列表,如果要拿到選擇結果,只需呼叫

List<CharSequence> checkedText = mCheckGroup.getCheckedText();

就可以拿到已選擇的列表的文字集合,或者呼叫

 List<Integer> checkedIndex = mCheckGroup.getCheckedIndex();

就可以拿到已選擇的列表的下標position集合,亦可呼叫

 List<Option> checked = mCheckGroup.getChecked();

就可以拿到已選擇的列表的物件集合,Option是一個實體累,OptionWrapper是對Option的一個簡單封裝類,兩個類裡面都是隻有3個欄位而已,程式碼就不貼了,可以自己下載原始碼檢視。

如需要把列表設定為單選列表,只需要在構造方法中傳入一個true即可,例如:

OptionWrapper optionWrapper = new OptionWrapper(true);

如果在單選時,通過optionWrapper.setChecked(1, 2, 4);方法設定了多個預設選中的選項,則只會取第一個有效值做為預設選中的選項;
如果在多選時,亦通過optionWrapper.setChecked(1, 2, 4);方法設定了n個預設選中的選項,假設共有10個選項,其中n>10,則會取前10個有效值做為預設選中的選項。何為有效值,請看程式碼:

    /**
     * 設定預設選中的item<br>
     * 注:此方法一定要在setOptions之後呼叫才會有效<br>
     * 單選時,預設取第一個有效值做為預設的選中
     *
     * @param positions 選中item的position集合
     */
    public void setChecked(List<Integer> positions) {
        if (positions == null || positions.size() == 0) return;
        for (int position : positions) {
            //當用戶傳過來的position大於等於集合的長度時,認為是無效值
            if (position >= mOptions.size()) continue;
            mOptions.get(position).setCheck(true);
            if (isSingleChoice) break;
        }
    }

如需設定監聽器,呼叫如下程式碼:

        mCheckGroup.setOnChangeListener(new CheckGroup.OnChangeListener() {
            @Override
            public void onChange(AdapterView<?> parent, View view, int position) {

            }
        });

監聽器看著眼熟是不是?沒錯,裡面的3個引數都是從ListView 的OnItemClickListener監聽器中傳過去的,因為CheckGroup繼承ListView,本質上就是一個ListView。

好了,基本就介紹到這裡了,怎麼樣,用起來是不是更簡單,更順手(沒有?那好吧,我會繼續努力的)

本人小白一個,各位大神如發現錯誤之處,請指出,本人感激不盡。