安卓Spinner关闭

14
我有一个带有下拉列表的活动界面,我想知道是否有可能在用户打开下拉列表时以编程方式将其关闭。
整个故事是这样的,后台我在单独的线程上运行一个进程。当进程完成时,我调用主Activity中的Handler,并根据结果执行某些任务。在此时,如果用户已经打开下拉列表,我想关闭它。
下拉列表在main.xml布局中。
<Spinner android:id="@+id/birthPlaceSpinner" android:layout_weight="1" 
android:layout_height="wrap_content" android:prompt="@string/select"
android:layout_width="fill_parent" />

这是处理程序:

private class BirthplaceChangedHandler extends Handler {

    @Override
    public void handleMessage(Message msg) {
        String placeFilterStr = birthPlaceFilterText.getText().toString();
        if ("".equals(placeFilterStr) || placeFilterStr == null || validNewAddresses.isEmpty()) {
            birthPlaceSpinner.setEnabled(false);
            hideGeoLocationInformation();
        } else {
            birthPlaceSpinner.setEnabled(true);
        }
        adapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.multiline_spinner_dropdown_item, validNewAddressesStr)
        birthPlaceSpinner.setAdapter(adapter);
    }
}

干杯!


你是如何创建/启动spinner的?你想做的几乎肯定是可能的,但你没有提供足够的信息来回答你的问题。代码片段可以帮助。 - i_am_jorf
重写Spinner.onDetachedFromWindow,将其公开并手动调用是我找到的唯一可行的方法。我遵循了http://stackoverflow.com/a/21122845/369317的建议。 - Denys Kniazhev-Support Ukraine
9个回答

22
  public static void hideSpinnerDropDown(Spinner spinner) {
    try {
        Method method = Spinner.class.getDeclaredMethod("onDetachedFromWindow");
        method.setAccessible(true);
        method.invoke(spinner);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

我得到了我所需要的。 - rodrigo.oliveira
非常顺利和轻松!非常感谢! - Parsania Hardik
这太聪明了,而且是唯一对我有效的方法。谢谢 +1 - Steven Foot

19

这对我有效:

class SomeAdapter extends BaseAdapter implements SpinnerAdapter {
    //......   
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if (view == null) {
            //......
        }
        view.setOnClickListener(new ItemOnClickListener(parent));
        return view;
    }
    //.....
}

并且点击监听器:

class ItemOnClickListener implements View.OnClickListener {
    private View _parent;

    public ItemOnClickListener(ViewGroup parent) {
        _parent = parent;
    }

    @Override
    public void onClick(View view) {
        //.......
        // close the dropdown
        View root = _parent.getRootView();
        root.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
        root.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
    }
}

9

这比我想象的要稍微复杂一些。

我在这里添加了详细的步骤。请尝试跟随它。我能够在API级别10中实现这一点。

此解决方案假定您应该在用户单击Home按钮或无需用户交互即可移动到下一个活动时,通过编程方式关闭提示对话框

第一步是通过扩展Spinner类创建自定义Spinner。 假设我已经在包com.bts.sampleapp中创建了一个名为CustomSpinner的类。

我的CustomSpinner类如下所示:

package com.bts.sampleapp;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;

    public class CustomSpinner extends Spinner{
        Context context=null;

        public CustomSpinner(Context context) {
            super(context);
            this.context=context;
        }

        public CustomSpinner(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        public CustomSpinner(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        @Override
        public void onDetachedFromWindow() {
            super.onDetachedFromWindow();
        }
    }

现在,在您的Xml文件中,将Spinner元素替换为此自定义Spinner。
        <com.bts.sampleapp.CustomSpinner
        android:id="@+id/spin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

下一步是在您的Activity类中初始化并设置适配器到这个下拉列表中。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    CustomSpinner spin=null;
    spin=(CustomSpinner)findViewById(R.id.spin);
    spin.setAdapter(spinnerAdapter); //you can set your adapter here.
}

最后一步是在用户单击HomeButton或活动进入后台时关闭对话框。为此,我们可以这样覆盖onPause()方法:
@Override
    protected void onPause() {
        Log.i("Life Cycle", "onPause");
        spin.onDetachedFromWindow();
        super.onPause();
    }

现在,在onPause()方法中调用spin.onDetachedFromWindow();方法,该方法会为您关闭提示对话框。

话虽如此,从Activity的任何位置调用spin.onDetachedFromWindow();都应该帮助您以编程方式关闭下拉列表。所以如果这就是您想要的,请移除onpause()方法。


8

我看不到任何实现的方法--在Spinner上没有关闭它的方法。 Spinner的“打开”部分是Android 1.x和2.x中的AlertDialog,当使用全息主题时,我不完全确定它是如何实现的。

唯一的解决办法就是克隆Spinner的源代码,并添加一些代码来关闭对话框。但是,同样地,在您能够看到并克隆那个代码之前,它将无法在Honeycomb或更高版本上工作。

除此之外,我认为你想要的会导致用户体验较差。如果用户打开了Spinner,他们很可能正在积极地检查Spinner的内容并进行选择。突然关闭会让他们感到困惑。请考虑其他方法。

此外,请不要使用getApplicationContext(),除非您知道为什么要使用getApplicationContext()。创建ArrayAdapter时不需要也不希望使用getApplicationContext()


3
我认为你应该放弃使用Spinner,而是使用一个带有Frame Animation(即<animation-list>)的ImageView来创建自己的Spinner。只需将ImageView的背景设置为您的Frame Animation drawable即可。
然后,您可以轻松地执行类似这样的操作来启动和停止它。

2
您想要在任何地方关闭您的旋转器。BACK键注入是一个好的解决方案,但是,这里您会一次性关闭所有视图。
那么使用setPressed(false)如何?
链接: 当组视图中的两个下拉列表同时被点击时关闭Spinners下拉列表 否则: 尝试将Spinner设置为focusable和focusableInTouchMode,并在其上使用clearFocus()。尝试使用requestFocus()方法聚焦于其下方的视图。
检查下拉列表是否关闭。

0
在代码中添加clearfocus()函数。
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.clearFocus();

在xml中使用透明背景

android:background="@android:color/transparent

<Spinner 
    android:id="@+id/spinner"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/transparent"
    android:clickable="false"
    android:focusable="?android:attr/windowOverscan"
    android:focusableInTouchMode="false"
    android:pointerIcon="arrow"
    android:spinnerMode="dialog"
    android:theme="@style/ThemeOverlay.AppCompat.Light" />

0
使用clearFocus()来编程地关闭Spinner。
spinner.clearFocus();

0

Kotlin 反射

fun AppCompatSpinner.dismiss() {
    val popup = AppCompatSpinner::class.java.getDeclaredField("mPopup")
    popup.isAccessible = true
    val listPopupWindow = popup.get(this) as ListPopupWindow
    listPopupWindow.dismiss()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接