代碼中通過 new Spinner(this) 動態創建,設置 setOnItemSelectedListener 但回調不執行,Toast 不彈出。
Spinner 必須掛載到 View 層級佈局中才會正常分發選中事件。動態創建但未 addView 到父容器,導致:
onAttachedToWindow 生命週期DropdownPopup 無法正確關聯窗口令牌performClick 時無法分發<!-- activity_layout.xml -->
<Spinner
android:id="@+id/hidden_spinner"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="invisible" />
// Activity/Fragment 中
Spinner spinner = findViewById(R.id.hidden_spinner);
ArrayAdapter adapter = new ArrayAdapter<>(this,
android.R.layout.simple_spinner_dropdown_item, dataList);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, "Selected: " + dataList.get(position), Toast.LENGTH_SHORT).show();
}
@Override
public void onNothingSelected(AdapterView> parent) {}
});
// 按鈕點擊觸發下拉
Button btn = findViewById(R.id.btn_show_spinner);
btn.setOnClickListener(v -> spinner.performClick());
// 1. 創建容器 (FrameLayout/LinearLayout)
FrameLayout container = findViewById(R.id.spinner_container);
// 2. 動態創建並添加到容器
Spinner spinner = new Spinner(this, Spinner.MODE_DROPDOWN); // API 11+
ArrayAdapter adapter = new ArrayAdapter<>(this,
android.R.layout.simple_spinner_dropdown_item, dataList);
spinner.setAdapter(adapter);
spinner.setLayoutParams(new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
container.addView(spinner); // 關鍵:必須添加到視圖樹
// 3. 設置監聽器 (必須在 addView 後或前均可,但需掛載)
spinner.setOnItemSelectedListener(listener);
// 4. 觸發
spinner.performClick();
// 完全自定義下拉選單,不依賴 Spinner 機制
ListPopupWindow popup = new ListPopupWindow(this);
popup.setAdapter(adapter);
popup.setAnchorView(anchorButton);
popup.setWidth(ListPopupWindow.WRAP_CONTENT);
popup.setHeight(ListPopupWindow.WRAP_CONTENT);
popup.setModal(true);
popup.setOnItemClickListener((parent, view, position, id) -> {
// 處理選中邏輯
popup.dismiss();
});
popup.show();
| 錯誤做法 | 後果 | 正確做法 |
|---|---|---|
new Spinner(context) 不加入佈局 | 事件不分發、崩潰風險 | XML 預置或 container.addView() |
spinner.setVisibility(GONE) | 同不加入佈局 | layout_width/height=0dp + invisible |
在 onCreate 前設置 listener | View 未初始化 | 在 onViewCreated / onActivityCreated 後設置 |
| 重複設置 Adapter | 位置重置觸發虛假選中 | 僅初始化一次,更新數據用 notifyDataSetChanged() |
public class FixedSpinner extends AppCompatSpinner {
private boolean firstSelection = true;
public FixedSpinner(Context context) { super(context); }
public FixedSpinner(Context context, AttributeSet attrs) { super(context, attrs); }
@Override
public void setSelection(int position, boolean animate) {
boolean shouldNotify = !firstSelection || position != getSelectedItemPosition();
super.setSelection(position, animate);
if (shouldNotify && getOnItemSelectedListener() != null) {
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
firstSelection = false;
}
}
addView 到父容器?getCount() > 0?setAdapter → setOnItemSelectedListenersetSelection(0) 導致初始選中不觸發?(預期行為)Spinner.MODE_DROPDOWN)