如何制作带有初始文本“Select One”的Android Spinner?

新手上路,请多包涵

我想使用最初(当用户尚未做出选择时)显示文本“选择一个”的 Spinner。当用户单击微调器时,将显示项目列表并且用户选择其中一个选项。用户做出选择后,所选项目将显示在 Spinner 中,而不是“Select One”。

我有以下代码来创建 Spinner:

 String[] items = new String[] {"One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

使用此代码,最初会显示项目“One”。我可以在项目中添加一个新项目“Select One”,但随后“Select One”也将作为第一项显示在下拉列表中,这不是我想要的。

我该如何解决这个问题?

原文由 Pieter Kuijpers 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 621
2 个回答

这是一个覆盖 Spinner 视图的通用解决方案。它覆盖 setAdapter() 将初始位置设置为 -1,并代理提供的 SpinnerAdapter 以显示位置小于 0 的提示字符串。

这已经在 Android 1.5 到 4.2 上进行了测试,但买家要小心!由于此解决方案依赖反射调用私有 AdapterView.setNextSelectedPositionInt()AdapterView.setSelectedPositionInt() ,因此不能保证在未来的操作系统更新中正常工作。看起来很可能会,但绝不能保证。

通常我不会容忍这样的事情,但是这个问题已经被问了足够多的时间,而且我认为我会发布我的解决方案似乎是一个足够合理的要求。

 /**
 * A modified Spinner that doesn't automatically select the first entry in the list.
 *
 * Shows the prompt if nothing is selected.
 *
 * Limitations: does not display prompt if the entry list is empty.
 */
public class NoDefaultSpinner extends Spinner {

    public NoDefaultSpinner(Context context) {
        super(context);
    }

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

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

    @Override
    public void setAdapter(SpinnerAdapter orig ) {
        final SpinnerAdapter adapter = newProxy(orig);

        super.setAdapter(adapter);

        try {
            final Method m = AdapterView.class.getDeclaredMethod(
                               "setNextSelectedPositionInt",int.class);
            m.setAccessible(true);
            m.invoke(this,-1);

            final Method n = AdapterView.class.getDeclaredMethod(
                               "setSelectedPositionInt",int.class);
            n.setAccessible(true);
            n.invoke(this,-1);
        }
        catch( Exception e ) {
            throw new RuntimeException(e);
        }
    }

    protected SpinnerAdapter newProxy(SpinnerAdapter obj) {
        return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(
                obj.getClass().getClassLoader(),
                new Class[]{SpinnerAdapter.class},
                new SpinnerAdapterProxy(obj));
    }

    /**
     * Intercepts getView() to display the prompt if position < 0
     */
    protected class SpinnerAdapterProxy implements InvocationHandler {

        protected SpinnerAdapter obj;
        protected Method getView;

        protected SpinnerAdapterProxy(SpinnerAdapter obj) {
            this.obj = obj;
            try {
                this.getView = SpinnerAdapter.class.getMethod(
                                 "getView",int.class,View.class,ViewGroup.class);
            }
            catch( Exception e ) {
                throw new RuntimeException(e);
            }
        }

        public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
            try {
                return m.equals(getView) &&
                       (Integer)(args[0])<0 ?
                         getView((Integer)args[0],(View)args[1],(ViewGroup)args[2]) :
                         m.invoke(obj, args);
            }
            catch (InvocationTargetException e) {
                throw e.getTargetException();
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        protected View getView(int position, View convertView, ViewGroup parent)
          throws IllegalAccessException {

            if( position<0 ) {
                final TextView v =
                  (TextView) ((LayoutInflater)getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE)).inflate(
                      android.R.layout.simple_spinner_item,parent,false);
                v.setText(getPrompt());
                return v;
            }
            return obj.getView(position,convertView,parent);
        }
    }
}

原文由 emmby 发布,翻译遵循 CC BY-SA 3.0 许可协议

使用轻量级和高度可定制的库查看答案:

https://stackoverflow.com/a/73085435/6694920

 <com.innowisegroup.hintedspinner.HintedSpinner
android:id="@+id/hintedSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
app:hintTextSize="24sp"
app:hintTextColor="@color/red"
app:hint="Custom hint"
app:withDivider="true"
app:dividerColor="@color/dark_green"
app:arrowDrawable="@drawable/example_arrow_4"
app:arrowTint="@color/colorAccent"
app:popupBackground="@color/light_blue"
app:items="@array/text" />

折叠的微调器: 在此处输入图像描述

扩展的微调器:

在此处输入图像描述

原文由 CraggyHaggy 发布,翻译遵循 CC BY-SA 4.0 许可协议

推荐问题