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

我有以下代码来创建一个旋转器:

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 lCreditOrDebit = (Spinner)lCardPayView.findViewById(R.id.CARD_TYPE);
spinneradapter lAdapter = 
  new spinneradapter(
    BillPayScreen.this, 
    ndroid.R.layout.simple_spinner_item,getResources().getStringArray(R.array.creditordebit));
lAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
lCreditOrDebit.setAdapter(lAdapter);

这里spinneradapter是对arrayadapter的一个小定制。它是这样的:

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

public class spinneradapter extends ArrayAdapter<String>{
    private Context m_cContext;
    public spinneradapter(Context context,int textViewResourceId, String[] objects) {
        super(context, textViewResourceId, objects);
        this.m_cContext = context;
    }

    boolean firsttime = true;
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(firsttime){
            firsttime = false;
            //Just return some empty view
            return new ImageView(m_cContext);
        }
        //Let the array adapter take care of it this time.
        return super.getView(position, convertView, parent);
    }
}

其他回答

下面是一个覆盖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);
        }
    }
}

似乎是一个平庸的解决方案,但我通常把简单的TextView在纺纱器的前面。整个Xml是这样的。(嘿,伙计们,别朝我开枪,我知道你们有些人不喜欢这种婚姻):

<FrameLayout
    android:id="@+id/selectTypesLinear"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <Spinner
        android:id="@+id/spinnerExercises"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:entries="@array/exercise_spinner_entries"
        android:prompt="@string/exercise_spinner_prompt"
     />                         
    <TextView
        android:id="@+id/spinnerSelectText"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hey! Select this guy!"
        android:gravity="center"
        android:background="#FF000000" />


</FrameLayout>

然后我隐藏TextView时,一个项目被选中。显然,TextView的背景颜色应该与旋转器相同。适用于Android 4.0。不知道旧版本。

是的。因为Spinner在开始时调用setOnItemSelectedListener,隐藏textview可能有点棘手,但可以这样做:

    Boolean controlTouched;

    exerciseSpinner.setOnTouchListener(new OnTouchListener() {


        @Override
        public boolean onTouch(View v, MotionEvent event) {
            controlTouched = true; // I touched it but but not yet selected an Item.
            return false;
        }

    });
    exerciseSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            if (controlTouched) { // Are you sure that I touched it with my fingers and not someone else  ?
                spinnerSelText.setVisibility(View.GONE);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0) {
        }

    });

如果您在从数据库游标填充项时遇到此问题,

我在这个SO答案中找到的最简单的解决方案:

在游标适配器查询中使用UNION,并将id= -1的附加项添加到查询结果中,而不真正将其添加到DB中:

喜欢的东西:

db.rawQuery("SELECT iWorkerId as _id, nvLastName as name  FROM  Worker
w  UNION  SELECT -1 as _id , '' as name",null);

如果选择的项目是-1,那么它是默认值。否则 这是桌子上的记录。

如果你只有三个选择,我只会使用带有RadioButtons的RadioGroup,你可以在一开始让它们都未选中。

对我来说,它是这样工作的。有改进,只改变文本在某些选项,而不是全部。

首先,我采用旋转器的名称并创建带有自定义视图的arrayadapter,但现在这并不重要,关键是覆盖getView,并在内部更改你需要更改的值。在我的情况下只有第一个,其余的我离开原来的

public void rellenarSpinnerCompeticiones(){
        spinnerArrayCompeticiones = new ArrayList<String>();
        for(Competicion c: ((Controlador)getApplication()).getCompeticiones()){
            spinnerArrayCompeticiones.add(c.getNombre());
        }
        //ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this,R.layout.spinner_item_competicion,spinnerArrayCompeticiones);
        ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this, R.layout.spinner_item_competicion, spinnerArrayCompeticiones){
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                final View v = vi.inflate(R.layout.spinner_item_competicion, null);
                final TextView t = (TextView)v.findViewById(R.id.tvCompeticion);
                if(spinnerCompeticion.getSelectedItemPosition()>0){
                    t.setText(spinnerArrayCompeticiones.get(spinnerCompeticion.getSelectedItemPosition()));
                }else{
                    t.setText("Competiciones");
                }
                return v;
            }
        };
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerCompeticion.setAdapter(spinnerArrayAdapter);
    }