如何使用RadioButton(kotlin)

如何使用RadioButton(kotlin)

情境

如果想要做一個單選的按鈕選單,可以使用 RadioButton 這個元件。

完整程式碼

如果你想要參考完整程式碼,可以參考我在 GitHub 上所寫的範例。

GitHub

程式碼說明

如果要加入兩個單選鈕,讓使用者能夠單一選擇其中一個選項。

方法一

如果要使用一個 RadioButton 你可以直接在程式內宣告,
先將xml改成LinearLayout且設定android:orientation="vertical"為垂直的
這樣就可以把兩個RadioButton加進去且不會重疊。

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.givemepass.radiobuttondemo.MainActivity">

</LinearLayout>

接著就把MainActivity加入兩個RadioButton

class MainActivity : AppCompatActivity() {  
 override fun onCreate(savedInstanceState: Bundle?) {  
  super.onCreate(savedInstanceState)  
  setContentView(R.layout.activity_main)  
  val programmer = RadioButton(this)  
  programmer.text = "程式設計師"  
  val designer = RadioButton(this)  
  designer.text = "UI設計師"  
  container.addView(programmer)  
  container.addView(designer)  
 }  
}

另外再將 xml 的 container 改成 LinearLayout,這樣一來就可以看到有兩個單選鈕跑出來了。
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  android:orientation="vertical"  
  xmlns:tools="http://schemas.android.com/tools"  
  android:id="@+id/container"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent"  
  tools:context=".MainActivity">  
</LinearLayout>

這時候你會發現一個問題, 就是同時兩個按下去都會變Enabled。

原來 RadioButton 外面還要再包一層 RadioGroup 才能達到這樣的效果。

  • 注意 : RadioGroup 是 LinearLayout 的子類別,排版方式預設是垂直的。
val programmer = RadioButton(this)  
programmer.text = "程式設計師"  
val designer = RadioButton(this)  
designer.text = "UI設計師"  
val group = RadioGroup(this)  
group.addView(programmer)  
group.addView(designer)  
container.addView(group)

變正常了。

不過隨著開發時間越來越久, 加入的元件就越來越多, 我們的RadioButton也越加越多, 這樣實在不是一個很好的管理方式。

###方法二
我們將元件宣告部分寫進XML, 會讓我們比較好管理,
布局也比較方便。
所以我們只要在XML寫入

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.givemepass.radiobuttondemo.MainActivity">
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <RadioButton
            android:text="程式設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <RadioButton
            android:text="UI設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RadioGroup>
</LinearLayout>

你會發現這樣的宣告方法比較乾淨且方便。


處理事件

如果要偵測事件可以有幾種方式來完成。

方法一

直接從 XML 設定,先把兩個 RadioButton 設定好 ID,並且讓它們指派 onClick 事件為 onSelect 方法。

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.givemepass.radiobuttondemo.MainActivity">
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <RadioButton
            android:onClick="onSelect"
            android:id="@+id/program"
            android:text="程式設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <RadioButton
            android:onClick="onSelect"
            android:id="@+id/ui"
            android:text="UI設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RadioGroup>
</LinearLayout>

接著在MainActivity宣告這個方法,再指派這個方法有三個重點。

  • 方法一定為 public
  • 回傳值一定要為 void
  • 傳入的參數一定是 View
fun onSelect(view: View) {  
    when (view.id) {  
        R.id.program -> Toast.makeText(this@MainActivity, "安安, 程式設計師!", Toast.LENGTH_SHORT).show()  
        R.id.ui -> Toast.makeText(this@MainActivity, "安安, UI設計師!", Toast.LENGTH_SHORT).show()  
    }  
}

如下圖就會看到事件跟View進行綁定了。



可是這樣會有一個問題就是會不好追蹤方法, 專案一大其實會找不太到方法被塞到哪邊去,因此,比較好的做法就是把事件寫到程式碼內。

方法二

我們先將 XML 的 onSelect 方法拿掉。

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.givemepass.radiobuttondemo.MainActivity">
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <RadioButton
            android:id="@+id/program"
            android:text="程式設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <RadioButton
            android:id="@+id/ui"
            android:text="UI設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RadioGroup>
</LinearLayout>

接著到 MainActivity 內加入事件的宣告,並且把它指定給 RadioButton,最後,再根據傳入的 ID 來辨識是哪個 RadioButton 被按下。

class MainActivity : AppCompatActivity() {  
 override fun onCreate(savedInstanceState: Bundle?) {  
  super.onCreate(savedInstanceState)  
  setContentView(R.layout.activity_main)  
  program.setOnCheckedChangeListener(mOnCheckedChangeListener)  
  ui.setOnCheckedChangeListener(mOnCheckedChangeListener)  
 }  
 private val mOnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, _ ->  
  when(buttonView.id){  
   R.id.program -> Toast.makeText(this@MainActivity, "安安, 程式設計師!", Toast.LENGTH_SHORT).show()  
   R.id.ui->Toast.makeText(this@MainActivity, "安安, UI設計師!", Toast.LENGTH_SHORT).show()  
  }  
 }  
}

看到的結果會跟用 xml 宣告的是一致的,結果如下圖。



設定 Style

既然 RadioButton 是View,那麼它就可以改變它的外觀。
在 Android SDK 內有內建許多 Icon 提供你使用, 路徑如下\AndroidSDK\platforms\android-24\data\res\drawable,我們就先透過下面這張預設圖來實作。


先在 xml 上面的 RadioButton 加入 background 屬性。

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.givemepass.radiobuttondemo.MainActivity">
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <RadioButton
            android:background="@android:drawable/radiobutton_off_background"
            android:id="@+id/program"
            android:text="程式設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <RadioButton
            android:background="@android:drawable/radiobutton_off_background"
            android:id="@+id/ui"
            android:text="UI設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RadioGroup>
</LinearLayout>

你就會看到我們將選取的(或自定義)的 drawable 被設定到 RadioButton 的 background。


畫面變得很奇怪, 因為改變樣式是不能透過 `android:background` 屬性的,應該是要用 `android:button` 這個屬性才對,xml 調整一下。
<RadioButton
    android:button="@android:drawable/radiobutton_off_background"
    android:id="@+id/program"
    android:text="程式設計師"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<RadioButton
    android:button="@android:drawable/radiobutton_off_background"
    android:id="@+id/ui"
    android:text="UI設計師"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

畫面變成我們想要的了,但是很詭異,為什麼按下去沒有效果呢? 原來我們設定 button 的時候,將預設的 selector 效果取代掉了,所以我們要自己來寫一個 selector,先一樣從SDK內取出打勾的效果,如下圖。

接著從 Android Studio 內點選 res 右鍵選擇 Drawable resource file,建立一個 radio_button_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="@android:drawable/radiobutton_off_background" />
<item android:state_checked="true" android:drawable="@android:drawable/radiobutton_on_background" />
</selector>

接著指派到原本的 activity_main.xml 內的 RadioButton。

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.givemepass.radiobuttondemo.MainActivity">
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <RadioButton
            android:button="@drawable/radio_selector"
            android:id="@+id/program"
            android:text="程式設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <RadioButton
            android:button="@drawable/radio_selector"
            android:id="@+id/ui"
            android:text="UI設計師"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RadioGroup>
</LinearLayout>

發現就出現我們想要的style了。


這樣就是一個簡單的 RadioButton 操作了。