Skip to main content

【Android】多行(Multi-row) RadioButton Group


在寫Android APP時,想要有多行RadioButton組成RadioGroup,但是RadioGroup又只認下一層的物件,對於下下層的子物件就會被忽視,所以無法以LinearLayout包裝一行行RadioButton的方式來達成。

最後在StackOverflow看到繼承TableLayout進行多行RadioButton實做的範例,在此做個使用方式的記錄,但是還不完全了解運作方式,待以後了解深入之後再來補。



作業環境:
使用Windows 7、Eclipse LUNA
Android SDK Platform-tools version 21
Android SDK Build-tools version 21.1.2
ADT version 24.0.2


程式主要概念:

使用者任意點選RadioButton,在點選取得字串按鍵後,會在按鍵下方顯示RadioButton後方的字串,簡易流程圖如下:

程式介面規畫示意圖:

Step 1. 撰寫xml,加入Button以及TextView物件

MainActivity.java所搭配的xml為預設的activity_main.xml,根據程式流程除了多行的RadioButtonGroup外,至少需要一個Button物件(btn_get)來觸發事件跟一個TextView物件(tvw_result)作為顯示字串用,參考程式碼以及Layout Outline如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Radio Button Group with 2 rows"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Button
android:id="@+id/btn_get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Get choosen radio button" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="The choosen option is: "
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/tvw_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

Step 2. 建立繼承TableLayout的客制類別ToggleButtonGroupTableLayout

接下來新建一個名為ToggleButtonGroupTableLayout.java的class,創建方法為右鍵點擊專案名稱,選擇New -> Class,編輯以下欄位:
Package欄位:建議將自行撰寫的view放置在另外的package較方便管理
Name欄位:輸入class名稱,同時也做為自定物件的名稱
Superclass欄位:選擇繼承TableLayout,點選Browse按鍵,輸入TableLayout進行搜尋。

上述欄位所在位置如下圖:

ToggleButtonGroupTableLayout.java之程式碼:
/**
*
*/
package com.custom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RadioButton;
import android.widget.TableLayout;
import android.widget.TableRow;
/**
* @author diego
*
*/
public class ToggleButtonGroupTableLayout extends TableLayout implements OnClickListener {
private static final String TAG = "ToggleButtonGroupTableLayout";
private RadioButton activeRadioButton;
/**
* @param context
*/
public ToggleButtonGroupTableLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
/**
* @param context
* @param attrs
*/
public ToggleButtonGroupTableLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
@Override
public void onClick(View v) {
final RadioButton rb = (RadioButton) v;
if ( activeRadioButton != null ) {
activeRadioButton.setChecked(false);
}
rb.setChecked(true);
activeRadioButton = rb;
}
/* (non-Javadoc)
* @see android.widget.TableLayout#addView(android.view.View, int, android.view.ViewGroup.LayoutParams)
*/
@Override
public void addView(View child, int index,
android.view.ViewGroup.LayoutParams params) {
super.addView(child, index, params);
setChildrenOnClickListener((TableRow)child);
}
/* (non-Javadoc)
* @see android.widget.TableLayout#addView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
@Override
public void addView(View child, android.view.ViewGroup.LayoutParams params) {
super.addView(child, params);
setChildrenOnClickListener((TableRow)child);
}
private void setChildrenOnClickListener(TableRow tr) {
final int c = tr.getChildCount();
for (int i=0; i < c; i++) {
final View v = tr.getChildAt(i);
if ( v instanceof RadioButton ) {
v.setOnClickListener(this);
}
}
}
public int getCheckedRadioButtonId() {
if ( activeRadioButton != null ) {
return activeRadioButton.getId();
}
return -1;
}
}
如此一來,客製的TableLayout類別ToggleButtonGroupTableLayout就完成了。其中public getCheckedRadioButtonId這個method可以讓我們在其他Activity中呼叫,取得被選取RadioButton的id。
若是要取得RadioButton的字串,可以新增如下的method:
public String getCheckedRadiobuttonStringText(){
if (activeRadioButton != null){
return activeRadioButton.getText().toString();
}
return "";
}
如有其他需要,也可以動手寫寫看!

Step 2. 編輯xml,將ToggleButtonGroupTableLayout放入介面中

將ToggleButtonGroupTableLayout放入xml介面編排中,程式碼及Layout Outline圖如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.custom.view.ToggleButtonGroupTableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/radgp_order"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TableRow>
<RadioButton
android:id="@+id/rad_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date"
android:textSize="20sp" />
<RadioButton
android:id="@+id/rad_rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rating"
android:textSize="20sp" />
<RadioButton
android:id="@+id/rad_relevance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Relevance"
android:textSize="20sp" />
</TableRow>
<TableRow>
<RadioButton
android:id="@+id/rad_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"
android:textSize="20sp" />
<RadioButton
android:id="@+id/rad_videoCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Video Count"
android:textSize="20sp" />
<RadioButton
android:id="@+id/rad_viewCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View Count"
android:textSize="20sp" />
</TableRow>
</com.custom.view.ToggleButtonGroupTableLayout>
</LinearLayout>
view raw radio_group.xml hosted with ❤ by GitHub
若想使用更多行的RadioButton,直接複製TableRow的區塊即可。
注意在使用ToggleButtonGroupTableLayout物件時,需要將該class所在的package也寫入,其格式為package_name.ToggleButtonGroupTableLayout,如按照先前設定的話,程式碼內容便是 "<com.custom.view.ToggleButtonGroupTableLayout ….",如果使用其他的package名稱,記得要改成相應名稱。

Step 3. 使用MainActivity內的全域變數進行資料傳遞

由於在經過一番嘗試之後,還是找不到方法在MainActivity內對ToggleButtonGroupTableLayout物件以類似setOnClickListener的方式插入RadioButton的點擊事件(只好在以後哪天開竅再回來補),只有ToggleButtonGroupTableLayout的onClick對選取RadioButton有反應。
因此決定先以比較迂迴的方式取得字串,先在MainActivity.java內新增一個全域的字串變數(result)作為儲存字串之用,然後當ToggleButtonGroupTableLayout物件onClick事件被觸發時,會將RadioButton的字串存入result。
MainActivity程式碼如下:
<script src="https://gist.github.com/NearLinHere/4f50a917421a43cff2de.js"></script> 另外在ToggleButtonGroupTableLayout.java內的onClick()添加取得字串以及賦值的部分:
<script src="https://gist.github.com/NearLinHere/faf28d2f4c200d9a185a.js"></script>

Step 3. 在MainActivity取得RadioButton的ID、字串值

首先使用ToggleButtonGroupTableLayout內的getCheckedRadioButtonId()方法取得RadioButton的ID,再cast成RadioButton的物件,接下就與操作一般RaioButton時相同,可以透過radioButton.getText().toString()取得字串值,程式碼如下:
package com.example.multirowradioboxgroup;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.TextView;
import com.custom.view.ToggleButtonGroupTableLayout;
public class MainActivity extends ActionBarActivity {
private String TAG = "MainActivity";
private ToggleButtonGroupTableLayout radio_gp;
private Button btn_getResult;
private TextView tv_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
radio_gp = (ToggleButtonGroupTableLayout)findViewById(R.id.radgp_order);
tv_result = (TextView)findViewById(R.id.tvw_result);
btn_getResult = (Button)findViewById(R.id.btn_get);
btn_getResult.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RadioButton checkedRadioButton = (RadioButton)findViewById(radio_gp.getCheckedRadioButtonId());
tv_result.setText(checkedRadioButton.getText().toString());
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
接下來便可以運行程式,點擊畫面上的按鈕後,會在下方顯示所選的RadioButton字串。
如果想讓程式碼更簡潔,可以使用Step 1.最後提到的getCheckedRadiobuttonStringText(),可以直接回傳字串值。

參考資料
[1] stackoverflow, How to group a 3x3 grid of radio buttons?
     Available from: http://stackoverflow.com/questions/2381560/how-to-group-a-3x3-grid-of-radio-buttons

Comments

Popular posts from this blog

淺介I2C

I 2 C 起源 內部整合電路( Inter-Integrated Circuit, I 2 C, 讀做 I-square-C )是由飛利浦半導體公司開發的一種專用介面。 I 2 C 是以最少的連接線進行硬體佈線還要有靈活擴充的特性為目標而設計,最後出現了只有以序列資料線 SDA ( Serial DAta )及序列時脈線 SCL ( Serial CLock )來進行所有通訊的 I 2 C 介面, I 2 C 允許多主( master )多僕( slave )系統,其傳輸系統內每一個裝置都有唯一的地址可供辨識。資料的寫入和讀取都是由 master 主動發起, slave 無法主動向 master 回報,除非使用中斷腳通知 master 。 I 2 C 傳輸速度有慢(小於 100Kbps )、快( 400Kbps )及高速( 3.4Mbps )三種,每一種均可向下相容。 I 2 C 電路配置 如前所述 I 2 C 為兩線式,一為時脈線 SCL ,另一條為資料線 SDA ,硬體線路如圖 1 ,兩線皆為雙向性,且都需要透過高接電阻( pull-up, 對岸說的上拉電阻)接電。平常不使用時, SCL 與 SDA 的訊號都處於高電位。為了多裝置共線的功能,裝置的 SCL 和 SDA 腳位要為 開洩極( open-drain ) 或 開集極( open-collector ) 。一旦有一個腳位的開洩極導通接地,則整條線都為低電位,這種現象稱作 wired-AND 運作 ;如同邏輯 AND 運算,需要共接的腳位都是 1 (開洩極斷路),該條線的電位才是 1 。如果沒有開洩極的腳位,可以使用具內部高接電阻的腳位,當要輸出 1 時,則設定該腳位為高接型輸入腳;而輸出為 0 時,則改設定為輸出腳並輸出 0 的值。 圖 1. I 2 C 傳輸裝置接線 [1] I 2 C 通訊協定 為使說明部分更簡潔,首先介紹幾個名詞: 位元傳輸協定 當 master 要跟 slave 溝通時,會先有個起始條件( start condition )的訊號,結束時也會送出終止條件( stop condition )訊號。起始條件訊號...

【Arduino】Timers, Registers, and Fast PWM Mode

由於Arduino預設的PWM控制方法僅有500Hz(好像還有另一個),想要知道怎樣才可以調整成其他頻率,以此做記錄。 先說明Timer設定方式、PWM Mode,之後會在Arduino上實做。 如果對_BV()沒有概念,可以參考 【Arduino I/O Ports】Control under avr-libc 這篇文章。

【Arduino】Control I/O pin by avr-libc

Arduino Ports and Register 心血來潮看了一下Arduino底層對pin腳的控制,整理了一下並且分為兩部分: 第一部分:Arduino內部pin腳的port以及register的編號,並且如何使用這些register對腳位進行控制 第二部分:使用最底層的avr-libc進行pinMode、digitalWrite函數的改寫練習,發現使用avr-libc可以有效降低script的大小