首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android Spinner 根據 RadioButton 動態切換資料源完整實作

     編輯:程式設計綜合問答

需求分析

頁面包含一組 RadioGroup(兩個 RadioButton)與一個 Spinner。根據用戶選擇的單選按鈕,Spinner 需動態載入不同的字串陣列資源(name_array 或 type_array)。核心邏輯在於:更換 Adapter 的資料集並通知更新。

資源定義 (res/values/arrays.xml)

<resources>
    <string-array name="name_array">
        <item>Alice</item>
        <item>Bob</item>
        <item>Charlie</item>
    </string-array>
    <string-array name="type_array">
        <item>Type A</item>
        <item>Type B</item>
        <item>Type C</item>
        <item>Type D</item>
    </string-array>
</resources>

佈局檔 (res/layout/activity_spinner_demo.xml)

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <RadioGroup
        android:id="@+id/rg_source"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/rb_names"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="人名"
            android:checked="true" />

        <RadioButton
            android:id="@+id/rb_types"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="類型" />
    </RadioGroup>

    <Spinner
        android:id="@+id/spinner_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp" />
</LinearLayout>

Activity 完整實作 (Kotlin)

class SpinnerDemoActivity : AppCompatActivity() {

    private lateinit var spinner: Spinner
    private lateinit var adapter: ArrayAdapter<String>
    private val nameArray by lazy { resources.getStringArray(R.array.name_array).toList() }
    private val typeArray by lazy { resources.getStringArray(R.array.type_array).toList() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_spinner_demo)

        spinner = findViewById(R.id.spinner_data)
        val rgSource = findViewById<RadioGroup>(R.id.rg_source)

        // 初始化 Adapter,預設顯示 name_array
        adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, nameArray)
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        spinner.adapter = adapter

        rgSource.setOnCheckedChangeListener { _, checkedId ->
            when (checkedId) {
                R.id.rb_names -> swapData(nameArray)
                R.id.rb_types -> swapData(typeArray)
            }
        }
    }

    private fun swapData(newData: List<String>) {
        adapter.clear()
        adapter.addAll(newData)
        adapter.notifyDataSetChanged() // 關鍵:通知 Spinner 重繪
    }
}

Java 版本對照

public class SpinnerDemoActivity extends AppCompatActivity {
    private Spinner spinner;
    private ArrayAdapter<String> adapter;
    private List<String> nameList, typeList;

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

        spinner = findViewById(R.id.spinner_data);
        RadioGroup rgSource = findViewById(R.id.rg_source);

        nameList = Arrays.asList(getResources().getStringArray(R.array.name_array));
        typeList = Arrays.asList(getResources().getStringArray(R.array.type_array));

        adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, nameList);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);

        rgSource.setOnCheckedChangeListener((group, checkedId) -> {
            if (checkedId == R.id.rb_names) swapData(nameList);
            else if (checkedId == R.id.rb_types) swapData(typeList);
        });
    }

    private void swapData(List<String> newData) {
        adapter.clear();
        adapter.addAll(newData);
        adapter.notifyDataSetChanged();
    }
}

關鍵技術點解析

  1. 同一 Adapter 實例複用:不必重新 new Adapter,直接 clear() + addAll() + notifyDataSetChanged(),效能更好、選中狀態保持更自然。
  2. RadioGroup.OnCheckedChangeListener:統一監聽單選組,避免對每個 RadioButton 單獨設 listener,邏輯集中。
  3. 資源陣列轉 List:Arrays.asList() 或 Kotlin .toList() 方便增刪改,ArrayAdapter 內部支援 List 操作。
  4. 預設選中項:XML 中 android:checked="true" 確保啟動時有確定資料源。

進階場景:資料源來自網路/資料庫

若資料非靜態資源,而是異步獲取,邏輯同樣適用:

// 協程異步獲取後
viewModel.getNames().observe(this, names -> {
    if (rbNames.isChecked) swapData(names); // 只有當前選中該源才更新
});
viewModel.getTypes().observe(this, types -> {
    if (rbTypes.isChecked) swapData(types);
});

常見錯誤避坑

  • ❌ 每次切換都 new ArrayAdapter() → 導致 Spinner 閃爍、選中位置重置。
  • ❌ 忘記 notifyDataSetChanged() → UI 不更新。
  • ❌ 在 OnCheckedChangeListener 中直接操作 spinner.setAdapter() → 同樣會重置狀態。

結語

Spinner 動態切換資料源的核心是 複用 Adapter 實例、操作其內部資料集、調用 notifyDataSetChanged()。配合 RadioGroup 統一監聽,代碼清晰且效能最優。此模式同樣適用於 ListView、RecyclerView 等 AdapterView 組件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved