我想使用一个微调器,最初(当用户还没有做出 Select 时)显示文本" Select 一个".当用户单击微调器时,将显示项目列表,并 Select 其中一个选项.用户进行 Select 后,所选项目将显示在微调器中,而不是" Select 一个".

我有以下代码来创建微调器:

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"也会在下拉列表中显示为第一个项目,这不是我想要的.

我如何解决这个问题?

推荐答案

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

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

通常情况下,我不会容忍这样的事情,但是这个问题已经被问了足够多次,这似乎是一个足够合理的要求,我想我应该发布我的解决方案.

/**
 * 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);
        }
    }
}

Android相关问答推荐

如何将Hilt添加到Android Studio中的Kotlin项目中?

如何消除脚手架和顶杆(material 3)更改 colored颜色 时的延迟?

如何从Android 12的来电中获取电话号码?

无法将非静态方法与Frida挂钩

将DiffUtils用于Android上的Recrecerview适配器

如何使用进度条和返回函数进行API调用,同时在Android上使用Kotlin保持高效?

从 Jetpack Compose 中的图像中删除默认高度

Android 导航 - 定义参数

为什么 Android Studio 中的 theme.xml 目录没有任何原色

需要在按钮 onclick 上从 string.xml 获取值. @Composable 调用只能在@Composable 函数的上下文中发生

当父布局的背景为浅色时,Android ProgressBar 背景 colored颜色 变为灰色

如何在 Android 的 ViewModel 中使用 LiveData

通知使用默认语言,屏幕显示多种语言,同时通过 AppCompatDelegate 设置应用程序语言

浏览器未命中断点判断 USB 连接设备

Kotlin File(path).walkTopDown() 找不到文件

如何在 Jetpack Compose 中设置行宽等于 TextField 的宽度?

Jetpack compose 为网络检索视频帧导致延迟

无法使用 Gradle 托管设备对基线配置文件运行测试

如何从 Jetpack Compose 中的 Radio 组中获取价值

ObjectBox,如何在冲突中放弃一切迁移?