如何在点击按钮时以编程方式修改Spinner的spinnerMode?
Hey there! I get your confusion—since Spinner doesn’t expose a public setter for its mode, modifying an already created instance isn’t straightforward. Let’s break down the solutions for you:
1. Using Reflection (Modify Existing Instance)
The spinner mode is stored in a private internal field mMode, so you can use reflection to update it directly on your existing spinner instance:
button.setOnClickListener { try { // Access the private mMode field val modeField = Spinner::class.java.getDeclaredField("mMode") modeField.isAccessible = true // Set the new mode (use Spinner.MODE_DIALOG for the dialog style) modeField.set(spinner, Spinner.MODE_DROPDOWN) // Refresh the spinner to apply changes spinner.adapter = spinner.adapter // Reset adapter to trigger redraw } catch (e: NoSuchFieldException) { e.printStackTrace() } catch (e: IllegalAccessException) { e.printStackTrace() } }
Caveats:
- Reflection relies on internal Android framework details, which might change across versions. While
mModehas been consistent for most recent Android releases, there’s no guarantee it won’t be renamed or removed in future updates.
2. Toggle Between Two Preconfigured Spinners (Recommended)
A more reliable and future-proof approach is to create two Spinner instances in your layout—one for each mode—and toggle their visibility when the button is clicked. This avoids reflection entirely:
Step 1: Add Both Spinners to Your Layout
<Spinner android:id="@+id/spinner_dropdown" android:layout_width="wrap_content" android:layout_height="wrap_content" android:spinnerMode="dropdown"/> <Spinner android:id="@+id/spinner_dialog" android:layout_width="wrap_content" android:layout_height="wrap_content" android:spinnerMode="dialog" android:visibility="gone"/>
Step 2: Sync Adapters and Toggle Visibility in Code
val spinnerDropdown = findViewById<Spinner>(R.id.spinner_dropdown) val spinnerDialog = findViewById<Spinner>(R.id.spinner_dialog) // Use the same adapter for both spinners to keep content consistent val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, listOf("Option 1", "Option 2", "Option 3")) spinnerDropdown.adapter = adapter spinnerDialog.adapter = adapter button.setOnClickListener { if (spinnerDropdown.visibility == View.VISIBLE) { // Switch to dialog mode spinnerDropdown.visibility = View.GONE spinnerDialog.visibility = View.VISIBLE // Sync selected position spinnerDialog.setSelection(spinnerDropdown.selectedItemPosition) } else { // Switch back to dropdown mode spinnerDialog.visibility = View.GONE spinnerDropdown.visibility = View.VISIBLE spinnerDropdown.setSelection(spinnerDialog.selectedItemPosition) } }
Why This is Better:
- No dependency on internal framework fields—compatible with all Android versions.
- More stable and easier to maintain, with no risk of breaking due to platform updates.
Why You Can't Use the Constructor for Existing Instances
The constructor you mentioned (Spinner(this, null, android.R.style.Widget_Spinner, Spinner.MODE_DROPDOWN)) creates a new Spinner instance, not modifies an existing one. Once a Spinner is initialized with a mode, that mode is set internally without a public API to change it—hence the need for either reflection or the toggle approach.
内容的提问来源于stack exchange,提问作者Cerber

