各位好~~ヾ(^∇^)

今天的主題是單選按鈕(Radio Button)的使用

在Android 設計中,不知道您是否遇過需要單訓的情形呢?

而如果這時你去搜尋Radio Button關鍵字的話

你應該會搜出很多教學。

但是!!(/・0・)

通常這些教學多數都是固定量的Radio Button

也就是使用xml介面寫好需要量的Radio Button,在去做控制。

不過~~在實際專案中大多數的需求其實都是要會變動的,反而要求不變動的應該算少...

也因如此才寫了這篇筆記_(:3」∠)_

在開始之前,以下是幾個建議的搜尋關鍵字,方便在搜尋的時候可以搜出自己想要的東西

 

dynamic radio button

自動生成Radio button

 

等以上兩個關鍵字,兩方配合一下就可以搜出"如何自動調整Radio Button的數量"要求囉!

(不過這篇主題就是要寫這個...)

另外,因為本次需要用到AlertDialog的相關技術

故,如果對於呼叫AlertDialog忘記的朋友

可以參考這篇 ->http://thumbb13555.pixnet.net/blog/post/310777160

另外,不想浪費時間的朋友,請直接拉到文章最後,有提供複製貼上就可以使用的Code (・ω・)b

OK,那就上範例

 

主畫面顯示範例

自動生成RadioButton畫面案例

 

AlertDialog內顯示範例

自動生成RadioButton的Dialog範例

奉上Github

https://github.com/thumbb13555/DynamicRaidoButtonExample

開始!


0.功能描述

  1. 在主畫面中按下按鈕後即顯示與轉輪號碼相等之RadioButton數量
  2. 按下右邊按鈕後即以AlertDialog顯示與轉輪號碼相等之RadioButton數量
  3. 主畫面中的RadioButton點選後顯示該RadioButton所對應之編號與標籤內容
  4. AlertDialog內點選完RadioButton點選OK即顯示該RadioButton所對應之編號與標籤內容

 

1.新增介面

這次要實作兩個介面,一個是主畫面;另一個是Dialog用的畫面

於是我的layout檔案中有兩個,兩個都要記得複製喔~

截圖 2020-01-12 下午12.51.54

然後奉上兩個介面連結

activity_main.xml

https://github.com/thumbb13555/DynamicRaidoButtonExample/blob/master/app/src/main/res/layout/activity_main.xml

截圖 2020-01-12 下午12.56.49

截圖 2020-01-12 下午1.00.45

choose_dialog.xml

https://github.com/thumbb13555/DynamicRaidoButtonExample/blob/master/app/src/main/res/layout/choose_dialog.xml

截圖 2020-01-12 下午12.57.11

截圖 2020-01-12 下午1.01.10

 

1.自動增減RadioButton的核心代碼介紹

核心代碼:

        /*取得標籤*/
        int rgAmount = numberPicker.getValue();//根據轉輪決定要有幾個標籤
        ArrayList<String> rgLabel = new ArrayList<>();

        for (int i = 0; i < rgAmount; i++) {
            rgLabel.add("第" + (i + 1) + "項目");
        }
        /*===================在此已完成標籤數量===================*/
        /*根據標籤數量設置幾個RadioButton*/
        LinearLayout layoutMain = findViewById(R.id.linearLayout_Main);//連結介面
        RadioGroup radioGroup = new RadioGroup(this);//新增RadioButton方法
        radioGroup.setOrientation(RadioGroup.VERTICAL);
        layoutMain.removeAllViewsInLayout();//清除原介面中的物件
        RadioGroup.LayoutParams rlTable;//設置界面
        for (int i = 0; i < rgLabel.size(); i++) {//以標籤數量決定新增幾個RadioButton
            RadioButton radioButton = new RadioButton(this);
            radioButton.setText(rgLabel.get(i));//設置每個RadioButton內的標籤名稱
            rlTable = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.MATCH_PARENT
                    , RadioGroup.LayoutParams.MATCH_PARENT);
            radioGroup.addView(radioButton, rlTable);//將創好的物件加入
        }
        layoutMain.addView(radioGroup);//將物件加入layout內

整體就如以上示範,只要複製就可以完成今天的基本需求

其整個邏輯重點就是在於"先把RadioButton創建好,然後再把RadioButton丟入RadioGroup內;最後再把RadioGroup丟入指定的Layout內"

這樣的一個過程

至於RadioGroup與RadioButton之間的關係

可以理解為RadioGroup是一個盤子

RadioButton是盤子裡的豆子

然後layout是一張桌子

一個桌子有很多盤子,每個盤子自成一區去控制他們

...我知道比喻很爛,不過大概是這樣...(´д`)

看過了核心代碼後,接下來就是加入周邊的程式了

 

2.置入功能

看過了核心代碼後,接下來就是要連結周邊元件

首先是onCreate內的框架設置

public class MainActivity extends AppCompatActivity {

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

        Button btDisplay = findViewById(R.id.button_display);
        Button btDialog = findViewById(R.id.button_showDialog);
        NumberPicker numberPicker = findViewById(R.id.numberPicker);

        numberPicker.setMaxValue(5);
        numberPicker.setMinValue(1);

        btDisplay.setOnClickListener((v) -> {
          //點擊左側按鈕後的行為

        });

        btDialog.setOnClickListener(v -> {
         //點擊右側按鈕後的行為

        });

    }
}

首先先寫一個副程式叫做setRadioAction,並將numbePicker元件傳入

public class MainActivity extends AppCompatActivity {

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

        Button btDisplay = findViewById(R.id.button_display);
        Button btDialog = findViewById(R.id.button_showDialog);
        NumberPicker numberPicker = findViewById(R.id.numberPicker);

        numberPicker.setMaxValue(5);
        numberPicker.setMinValue(1);

        btDisplay.setOnClickListener((v) -> {
            setRadioAction(numberPicker);

        });

        btDialog.setOnClickListener(v -> {
         
        });

    }
   
    /**
     * 設置主畫面上的RadioButton
     */
    private void setRadioAction(NumberPicker numberPicker) {
        
    }
}

接著焦點放在這個副程式內,首先我們要先來生成radioButton附帶的標籤

於是程式長這樣

     /**
     * 設置主畫面上的RadioButton
     */
    private void setRadioAction(NumberPicker numberPicker) {
        /*取得標籤*/
        int rgAmount = numberPicker.getValue();
        ArrayList<String> rgLabel = new ArrayList<>();

        for (int i = 0; i < rgAmount; i++) {
            rgLabel.add("第" + (i + 1) + "項目");
        }
        Log.d(TAG, "setRadioAction: "+rgLabel);
       
    }

看一下Logcat:

截圖 2020-01-12 下午2.16.41

可以看見我們標籤項目有四個了

再來就是加入介面及方法

/**
     * 設置主畫面上的RadioButton
     */
    private void setRadioAction(NumberPicker numberPicker) {
        /*取得標籤*/
        int rgAmount = numberPicker.getValue();
        ArrayList<String> rgLabel = new ArrayList<>();

        for (int i = 0; i < rgAmount; i++) {
            rgLabel.add("第" + (i + 1) + "項目");
        }
        Log.d(TAG, "setRadioAction: "+rgLabel);
        /*根據標籤數量設置幾個RadioButton*/
        LinearLayout layoutMain = findViewById(R.id.linearLayout_Main);
        RadioGroup radioGroup = new RadioGroup(this);
        radioGroup.setOrientation(RadioGroup.VERTICAL);
        layoutMain.removeAllViewsInLayout();
        RadioGroup.LayoutParams rlTable;
        
    }

在這邊要特別注意反綠的部分一定要加,不然最後出現結果會這樣

自動生成radioButton失敗案例

無限增加...(´ж`;)

最後是將RadioButton放進RadioGroup的部分

然後迴圈外就是把RadioGroup放入layout內

/**
     * 設置主畫面上的RadioButton
     */
    private void setRadioAction(NumberPicker numberPicker) {
        /*取得標籤*/
        int rgAmount = numberPicker.getValue();
        ArrayList<String> rgLabel = new ArrayList<>();

        for (int i = 0; i < rgAmount; i++) {
            rgLabel.add("第" + (i + 1) + "項目");
        }
        Log.d(TAG, "setRadioAction: "+rgLabel);
        /*根據標籤數量設置幾個RadioButton*/
        LinearLayout layoutMain = findViewById(R.id.linearLayout_Main);
        RadioGroup radioGroup = new RadioGroup(this);
        radioGroup.setOrientation(RadioGroup.VERTICAL);
        layoutMain.removeAllViewsInLayout();
        RadioGroup.LayoutParams rlTable;

        for (int i = 0; i < rgLabel.size(); i++) {
            RadioButton radioButton = new RadioButton(this);
            radioButton.setText(rgLabel.get(i));
            rlTable = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.MATCH_PARENT
                    , RadioGroup.LayoutParams.MATCH_PARENT);
            radioGroup.addView(radioButton, rlTable);
        }
        layoutMain.addView(radioGroup);
        
    }

Ok,到此為止程式就完成了( ゚Д゚)b

按下執行看一下吧~

自動生成RadioButton成功處理

3.加入點擊事件

接著我們要為RadioButton加入點擊事件

目標是要點擊後取得兩項資訊-RadioButton的內容以及其代表的position(在Group內的Id)

而對應其點擊的方法就是setOnCheckedChangeListener方法

截圖 2020-01-12 下午2.46.21

直接上程式

lambda表示法:

radioGroup.setOnCheckedChangeListener(((group, checkedId) -> {
            
        }));

一般表示法:

radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {

            }
        });

哇!真貼心!回傳checkId耶(゜ロ゜)

這樣是不是只要標籤陣列"rgLabel"然後rgLabel.get(checkedId);就大功告成了呢?

廢話,我會這樣講,表示肯定有詐

我們來觀察一下checkId會回傳什麼

OK執行開始(-ω-ゞ

首先轉輪到五,然後點擊第四選項

截圖 2020-01-12 下午2.57.10

恩看起來沒問題

再來點3

截圖 2020-01-12 下午2.57.18

好,OK

點1

截圖 2020-01-12 下午2.57.26

再來轉輪切到3組,按下顯示,然後點擊第三項目

截圖 2020-01-12 下午2.57.35

恩?

截圖 2020-01-12 下午2.57.39

下載

截圖 2020-01-12 下午2.57.51

下載 (1)

 

花!惹!發?

之前第一次遇到問題時這是我心中第一個想法....

tenor

好啦既然我會PO表示解決了(∩╹□╹∩)

這時候我是搜尋CSDN論壇,keyWord為

RadioGroup.OnCheckedChangeListener checkedId累加

我直接說結論

結論是這算是這個套件的小Bug之一

如果一直重新載入的話,就會造成ID一直累加

因此我翻了好久官網文件才找到方法

好在RadioButton有提供一種方法叫做getCheckedRadioButtonId()

他是可以幫助你標示出你選中的RadioButton其對應的xml ID

於是我們先新增一個RadioButton,然後逆向操作從其ID身上獲取資訊就可以了

其次兩行也順便講,取得到該RadioButton後,就可以再進一步取得他對應於Group內的ID以及他標籤的名稱

如此這般如此這般~這樣就完成囉!

         radioGroup.setOnCheckedChangeListener(((group, checkedId) -> {
            RadioButton radioButton = findViewById(group.getCheckedRadioButtonId());
            String getLab = radioButton.getText().toString();
            int getGroupId = group.indexOfChild(radioButton);
            Toast.makeText(this, getLab + ", id=" + getGroupId, Toast.LENGTH_LONG).show();
        }));

另外提醒,在回傳中的group其實就是回傳RadioGroup本身

因此就算沒有這個override,一樣可以獲取到標籤的相關資訊喔

自動生成RadioButton畫面案例

4.套入到Dialog內

套入到AlertDialog內的方法大同小異,並沒有別的不同

我直接上程式,用標注的方法來講解吧

public class MainActivity extends AppCompatActivity {
    public static final String TAG = MainActivity.class.getSimpleName() + "My";

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

        Button btDisplay = findViewById(R.id.button_display);
        Button btDialog = findViewById(R.id.button_showDialog);
        NumberPicker numberPicker = findViewById(R.id.numberPicker);

        numberPicker.setMaxValue(5);
        numberPicker.setMinValue(1);

        btDisplay.setOnClickListener((v) -> {
            setRadioAction(numberPicker);

        });

        btDialog.setOnClickListener(v -> {
            setDialogRadioAction(numberPicker);

        });

    }//End onCreate
    /**
     * 設置Dialog上的RadioButton
     */
    private void setDialogRadioAction(NumberPicker numberPicker) {
        /*取得標籤*/
        int rgAmount = numberPicker.getValue();
        ArrayList<String> rgLabel = new ArrayList<>();

        for (int i = 0; i < rgAmount; i++) {
            rgLabel.add("第" + (i + 1) + "項目");
        }
        /*設置AlertDialog以及內容物*/
        AlertDialog.Builder mBuilder = new AlertDialog.Builder(this);
        View view = getLayoutInflater().inflate(R.layout.choose_dialog, null);
        mBuilder.setView(view);
        /*根據標籤數量設置幾個RadioButton*/
        LinearLayout layoutDialog = view.findViewById(R.id.linearLayout_Dialog);
        RadioGroup radioGroup = new RadioGroup(this);
        radioGroup.setOrientation(RadioGroup.VERTICAL);
        layoutDialog.removeAllViewsInLayout();
        RadioGroup.LayoutParams rlTable;
        for (int i = 0; i < rgLabel.size(); i++) {
            RadioButton radioButton = new RadioButton(this);
            radioButton.setText(rgLabel.get(i));
            rlTable = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.MATCH_PARENT
                    , RadioGroup.LayoutParams.MATCH_PARENT);
            radioGroup.addView(radioButton, rlTable);
        }
        layoutDialog.addView(radioGroup);

        /*設置點擊事件*/
        mBuilder.setNegativeButton("取消", null);
        mBuilder.setPositiveButton("OK", (dialog, which) -> {
            try {
                RadioButton radioButton = view.findViewById(radioGroup.getCheckedRadioButtonId());
                String getDialogLab = radioButton.getText().toString();
                int getDialogId= radioGroup.indexOfChild(radioButton);
                Toast.makeText(this, getDialogLab + ", id=" + getDialogId, Toast.LENGTH_LONG).show();
            }catch (Exception e){
                Toast.makeText(this, "未點選任何項目", Toast.LENGTH_LONG).show();
            }

        });

        mBuilder.show();
    }
}

藍色部分是關於AlertDialog的設置

唯一需要注意的是,所有呼叫findViewById的部分,都記得要加入"view.findViewById"(有粗體標註)

否則程式會出錯喔!

至於對於AlertDialog不熟的朋友,可參考

這篇->http://thumbb13555.pixnet.net/blog/post/310777160

希望對你有幫助~


結論

首先補上可直接copy走的副程式

/**直接複製區域*/
    private void copy(int amount,LinearLayout layout){
        ArrayList<String> rgLabel = new ArrayList<>();
        for (int i = 0; i < amount; i++) {
            rgLabel.add("第" + (i + 1) + "項目");
        }
        /*根據標籤數量設置幾個RadioButton*/
        RadioGroup radioGroup = new RadioGroup(this);
        radioGroup.setOrientation(RadioGroup.VERTICAL);
        layout.removeAllViewsInLayout();
        RadioGroup.LayoutParams rlTable;
        for (int i = 0; i < rgLabel.size(); i++) {
            RadioButton radioButton = new RadioButton(this);
            radioButton.setText(rgLabel.get(i));
            rlTable = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.MATCH_PARENT
                    , RadioGroup.LayoutParams.MATCH_PARENT);
            radioGroup.addView(radioButton, rlTable);
        }
        layout.addView(radioGroup);
        /*設置點擊事件*/
        /*點擊並獲取標籤內容與"真正的"ID*/
        radioGroup.setOnCheckedChangeListener(((group, checkedId) -> {
            RadioButton radioButton = findViewById(group.getCheckedRadioButtonId());
            String getLab = radioButton.getText().toString();
            int getGroupId = group.indexOfChild(radioButton);
            Toast.makeText(this, getLab + ", id=" + getGroupId, Toast.LENGTH_LONG).show();
        }));
    }

傳入值為: copy(int 多少個RadioButton, LinearLayout 放置RadioGroup的Layout)

copy(numberPicker.getValue(),findViewById(R.id.linearLayout_Main));

 

RadioButton不算是太難的元件

但是要設計得可以自由增減也是要花一定的功夫處理

我之前在網路搜集相關資料時基本上還是以大陸的CSDN跟英文搜尋結果為主

希望看到這裡的你,能夠正常的運作今天的功能

1572096350550

 

arrow
arrow

    碼農日常 發表在 痞客邦 留言(1) 人氣()