ChatGPT解决这个技术问题 Extra ChatGPT

如何制作带有初始文本“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”也将作为第一项显示在下拉列表中,这不是我想要的。

我该如何解决这个问题?

完美的解决方案在于这个问题:stackoverflow.com/questions/9863378/… 只需覆盖 getDropDownView() 方法。
您是否尝试将适配器的第一个元素设置为“选择一个”?
[这里还有其他很棒的解决方案!][1] [1]: stackoverflow.com/questions/9863378/…
可重复使用的微调器:github.com/henrychuangtw/ReuseSpinner

C
Cœur

您可以做的是装饰您的 SpinnerAdapter,其中显示一个“选择选项...”视图,以便微调器在没有选择任何内容的情况下显示。

这是一个针对 Android 2.3 和 4.0 测试的工作示例(它不使用兼容性库中的任何内容,所以一段时间内应该没问题)因为它是一个装饰器,所以应该很容易改造现有代码并且它可以与 CursorLoader 一起正常工作s 也。 (当然,在包装的 cursorAdapter 上交换光标......)

有一个 Android 错误使重用视图变得更加困难。 (因此您必须使用 setTag 或其他东西来确保您的 convertView 正确。)Spinner does not support multiple view types

代码注释:2个构造函数

这允许您使用标准提示或将您自己的“未选择任何内容”定义为第一行,或两者兼而有之,或无。 (注意:某些主题显示 Spinner 的 DropDown 而不是对话框。Dropdown 通常不显示提示)

您将布局定义为“看起来”像一个提示,例如,灰显...

https://i.stack.imgur.com/aEL12.png

使用标准提示(注意没有选择任何内容):

https://i.stack.imgur.com/zFvtw.png

或者有提示和动态的东西(也可能没有提示):

https://i.stack.imgur.com/TRDiy.png

上面例子中的用法

Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.planets_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setPrompt("Select your favorite Planet!");

spinner.setAdapter(
      new NothingSelectedSpinnerAdapter(
            adapter,
            R.layout.contact_spinner_row_nothing_selected,
            // R.layout.contact_spinner_nothing_selected_dropdown, // Optional
            this));

contact_spinner_row_nothing_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="?android:attr/spinnerItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textSize="18sp"
    android:textColor="#808080"
    android:text="[Select a Planet...]" />

NothingSelectedSpinnerAdapter.java

import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;

/**
 * Decorator Adapter to allow a Spinner to show a 'Nothing Selected...' initially
 * displayed instead of the first choice in the Adapter.
 */
public class NothingSelectedSpinnerAdapter implements SpinnerAdapter, ListAdapter {

    protected static final int EXTRA = 1;
    protected SpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    /**
     * Use this constructor to have NO 'Select One...' item, instead use
     * the standard prompt or nothing at all.
     * @param spinnerAdapter wrapped Adapter.
     * @param nothingSelectedLayout layout for nothing selected, perhaps
     * you want text grayed out like a prompt...
     * @param context
     */
    public NothingSelectedSpinnerAdapter(
      SpinnerAdapter spinnerAdapter,
      int nothingSelectedLayout, Context context) {

        this(spinnerAdapter, nothingSelectedLayout, -1, context);
    }

    /**
     * Use this constructor to Define your 'Select One...' layout as the first
     * row in the returned choices.
     * If you do this, you probably don't want a prompt on your spinner or it'll
     * have two 'Select' rows.
     * @param spinnerAdapter wrapped Adapter. Should probably return false for isEnabled(0)
     * @param nothingSelectedLayout layout for nothing selected, perhaps you want
     * text grayed out like a prompt...
     * @param nothingSelectedDropdownLayout layout for your 'Select an Item...' in
     * the dropdown.
     * @param context
     */
    public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
            int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context) {
        this.adapter = spinnerAdapter;
        this.context = context;
        this.nothingSelectedLayout = nothingSelectedLayout;
        this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
        layoutInflater = LayoutInflater.from(context);
    }

    @Override
    public final View getView(int position, View convertView, ViewGroup parent) {
        // This provides the View for the Selected Item in the Spinner, not
        // the dropdown (unless dropdownView is not set).
        if (position == 0) {
            return getNothingSelectedView(parent);
        }
        return adapter.getView(position - EXTRA, null, parent); // Could re-use
                                                 // the convertView if possible.
    }

    /**
     * View to show in Spinner with Nothing Selected
     * Override this to do something dynamic... e.g. "37 Options Found"
     * @param parent
     * @return
     */
    protected View getNothingSelectedView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedLayout, parent, false);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
        // Spinner does not support multiple view types
        if (position == 0) {
            return nothingSelectedDropdownLayout == -1 ?
              new View(context) :
              getNothingSelectedDropdownView(parent);
        }

        // Could re-use the convertView if possible, use setTag...
        return adapter.getDropDownView(position - EXTRA, null, parent);
    }

    /**
     * Override this to do something dynamic... For example, "Pick your favorite
     * of these 37".
     * @param parent
     * @return
     */
    protected View getNothingSelectedDropdownView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedDropdownLayout, parent, false);
    }

    @Override
    public int getCount() {
        int count = adapter.getCount();
        return count == 0 ? 0 : count + EXTRA;
    }

    @Override
    public Object getItem(int position) {
        return position == 0 ? null : adapter.getItem(position - EXTRA);
    }

    @Override
    public int getItemViewType(int position) {
        return 0;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public long getItemId(int position) {
        return position >= EXTRA ? adapter.getItemId(position - EXTRA) : position - EXTRA;
    }

    @Override
    public boolean hasStableIds() {
        return adapter.hasStableIds();
    }

    @Override
    public boolean isEmpty() {
        return adapter.isEmpty();
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        adapter.registerDataSetObserver(observer);
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        adapter.unregisterDataSetObserver(observer);
    }

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }

    @Override
    public boolean isEnabled(int position) {
        return position != 0; // Don't allow the 'nothing selected'
                                             // item to be picked.
    }

}

这是一个优雅的解决问题的方法。代码的工作方式与复制粘贴到我的项目中完全相同。 +1 不需要反射。
这是一个很好的解决方案。如果有人想知道如何不仅在选择项目之前覆盖标题,而且在任何时候,在 getView() 调用中,只需始终返回 getNothingSelectedView (或任何其他自定义视图)。下拉列表仍将填充来自适配器的项目,但您现在也可以在选择某些内容后控制标题。
对于不应该存在的问题,这是一个非常优雅的解决方案(尝试 Iphone 开发)。太好了,谢谢!很高兴有人记得模式等。
@prashantwosti,代码已更新以与 Lollipop 一起使用。特别是 getItemViewType() 和 getViewTypeCount()。
@aaronvargas 一旦从微调器中选择了一个项目,我可以撤消并选择“[选择行星]”吗?
e
emmby

这是覆盖 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您知道用户设置后如何清除选择吗?我尝试将两个 invoke() 调用重构为 clearSelection() 方法,但它并没有真正起作用。尽管弹出列表将以前选择的项目显示为未选择,但微调器小部件仍将其显示为已选择,如果用户再次选择相同的项目,则不会调用 onItemSelected()。
有人能解释一下如何使用上面的类吗?
这个解决方案在 Android 4.2 (Cyanogenmod 10.1) 上不是 100% 完美的,使用 android:entries。膨胀的 TextView 的高度小于默认适配器膨胀的任何资源的高度。因此,当您实际选择一个选项时,高度会增加,在我的 Galaxy S 中约为 10 像素,这是不可接受的。我已经尝试了几件事(重力、填充、边距等),但没有一个能在设备上可靠地工作,所以我将选择不同的解决方案。
@DavidDoria您必须在布局文件中使用 NoDefaultSpinner 类。将上面的源代码复制到您的项目中,例如,复制到包 com.example.customviews 中。现在在您的布局 xml 中,而不是 使用 其余代码可以保持不变。不要忘记将 android:prompt 属性添加到布局中的 视图中。
@emmby spinnerBrand.setSelection(-1);不管用
H
HRJ

我最终改用了 Button。虽然 Button 不是 Spinner,但其行为很容易自定义。

首先像往常一样创建适配器:

String[] items = new String[] {"One", "Two", "Three"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_spinner_dropdown_item, items);

请注意,我使用 simple_spinner_dropdown_item 作为布局 ID。这将有助于在创建警报对话框时创建更好的外观。

在我的 Button 的 onClick 处理程序中,我有:

public void onClick(View w) {
  new AlertDialog.Builder(this)
  .setTitle("the prompt")
  .setAdapter(adapter, new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

      // TODO: user specific action

      dialog.dismiss();
    }
  }).create().show();
}

就是这样!


我同意这个答案。此外,一个按钮比 Spinner 更容易设计样式。
@HRJ我已经实现了你建议的方式,但是之前选择的项目没有被突出显示(意味着单选按钮必须在中间用绿点突出显示)......我如何在 OnClick() 方法中实现这一点按钮。请帮助我HRJ.....
这个布局的按钮是完美的
然后,您将如何更新按钮的文本以反映选择,就像在微调器中发生的那样?
问题解决方案:只是使用 SetSingleChoiceItems 而不是 SetAdapter
S
Suragch

首先,您可能对 Spinner 类的 prompt 属性感兴趣。见下图,“Choose a Planet”是可以用android:prompt=""在XML中设置的提示。

https://i.stack.imgur.com/4a3Na.png

我将建议子类化 Spinner,您可以在其中内部维护两个适配器。一个具有“选择一个”选项的适配器,另一个 real 适配器(具有实际选项),然后在显示选择对话框之前使用 OnClickListener 切换适配器。但是,在尝试实现该想法后,我得出的结论是您无法接收到小部件本身的 OnClick 事件。

您可以将微调器包装在不同的视图中,拦截视图上的点击,然后告诉您的 CustomSpinner 切换适配器,但这似乎是一个可怕的 hack。

你真的需要显示“选择一个”吗?


这不仅仅是需要显示“选择一个”的问题,它还解决了微调器值可以选择留空的情况。
此外,使用此选项,地球在选择任何内容之前显示为 Spinner 上的选择,对于我的应用程序,我希望用户能够告诉他们尚未选择任何内容
这并没有真正回答这个问题。人们正在寻找一种方法让微调器本身默认显示“选择一个”而不是行星列表中的第一项,在这个例子中
M
Manos

此代码已经过测试,可在 Android 4.4 上运行

https://i.stack.imgur.com/onnOf.png

Spinner spinner = (Spinner) activity.findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity, android.R.layout.simple_spinner_dropdown_item) {

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {

                View v = super.getView(position, convertView, parent);
                if (position == getCount()) {
                    ((TextView)v.findViewById(android.R.id.text1)).setText("");
                    ((TextView)v.findViewById(android.R.id.text1)).setHint(getItem(getCount())); //"Hint to be displayed"
                }

                return v;
            }       

            @Override
            public int getCount() {
                return super.getCount()-1; // you dont display last item. It is used as hint.
            }

        };

        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        adapter.add("Daily");
        adapter.add("Two Days");
        adapter.add("Weekly");
        adapter.add("Monthly");
        adapter.add("Three Months");
        adapter.add("HINT_TEXT_HERE"); //This is the text that will be displayed as hint.


        spinner.setAdapter(adapter);
        spinner.setSelection(adapter.getCount()); //set the hint the default selection so it appears on launch.
        spinner.setOnItemSelectedListener(this);

getItem(getCount()) 对我来说是红色下划线吗?无法解析方法 setHint
我有一个疑问,在这个线程中看到了很多解决方案..但是为什么每个人都在最后添加提示。在第一行添加提示是错误的吗?
我无法设置 'setOnItemSelectedListener(this);'因为我正在使用“实现 NavigationView.OnNavigationItemSelectedListener”,我可以删除“setOnItemSelectedListener(this);”吗没有任何问题?
@akashpatra 他们最后添加提示的原因是用于微调器的 ArrayAdapter 可能会在运行时从不同的来源获取其值。
这真的帮助了我
P
Peter Mortensen

我找到了这个解决方案:

String[] items = new String[] {"Select 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);

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
        items[0] = "One";
        selectedItem = items[position];
    }

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

只需使用“Select One”更改数组 [0],然后在 onItemSelected 中将其重命名为“One”。

不是一个经典的解决方案,但它有效:D


这对我不起作用。选择项目“一个”后,它仍然显示“选择一个”。
这不会起作用,因为 onItemSelected 接口总是第一次调用。
m
mjancola

这里有很多答案,但我很惊讶没有人提出一个简单的解决方案:在 Spinner 顶部放置一个 TextView。在 TextView 上设置一个点击监听器,它隐藏 TextView 显示 Spinner,并调用 spinner.performClick()。


这是我最喜欢的答案。谢谢。
Y
Yakiv Mospan

没有默认 API 可以在 Spinner 上设置提示。要添加它,我们需要一个小的解决方法,而不是安全反射实现

List<Object> objects = new ArrayList<Object>();
objects.add(firstItem);
objects.add(secondItem);
// add hint as last item
objects.add(hint);

HintAdapter adapter = new HintAdapter(context, objects, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

Spinner spinnerFilmType = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);

// show hint
spinner.setSelection(adapter.getCount());

适配器来源:

public class HintAdapter
        extends ArrayAdapter<Objects> {

    public HintAdapter(Context theContext, List<Object> objects) {
        super(theContext, android.R.id.text1, android.R.id.text1, objects);
    }

    public HintAdapter(Context theContext, List<Object> objects, int theLayoutResId) {
        super(theContext, theLayoutResId, android.R.id.text1, objects);
    }

    @Override
    public int getCount() {
        // don't display last item. It is used as hint.
        int count = super.getCount();
        return count > 0 ? count - 1 : count;
    }
}

Original source


什么是 R.id.text1 ?它是任何布局或视图吗?请详细说明你的答案
它应该是 android.R.id.text1
我有一个疑问,在这个线程中看到了很多解决方案..但是为什么每个人都在最后添加提示。在第一行添加提示是错误的吗?
@akashpatra 我不记得确切,但是当我尝试将其作为第一个项目列表时似乎存在一些问题。无论如何,您可以随时尝试并在这里发表评论,这里所有的魔法都围绕着 getCount 方法
@YakivMospan 我在使用它时得到一个 NPE,可能是由于使用 ProGuard 时的反射。你知道如何解决这个问题吗?
P
Peter Mortensen

我在微调器上遇到了同样的问题,选择为空,我找到了更好的解决方案。看看这个简单的代码。

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

这种方法的问题是当列表弹出时它仍然选择列表中的第一项。因为它已经被选中,所以你不能触摸它来选择——它就像没有发生任何选择一样。
C
Cabezas

这是我的方式:

List<String> list = new ArrayList<String>();
list.add("string1");
list.add("string2");
list.add("string3");
list.add("[Select one]");
final int listsize = list.size() - 1;
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list) {
 @Override
public int getCount() {
    return(listsize); // Truncate the list
}
};
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

mySpinner.setSelection(listsize); // Hidden item to appear in the spinner

这会在底部位置打开微调器
在浪费了几个小时之后……!!!非常感谢您的解决方案
C
Christian Vielma

您可以将其更改为文本视图并使用它:

android:style="@android:style/Widget.DeviceDefault.Light.Spinner"

然后定义 android:text 属性。


仅适用于 API 14 及更高版本。
P
Peter Mortensen

XML 文件:

<Spinner android:id="@+id/locationSpinner"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:prompt="@string/select_location" />

活动:

private Spinner featuresSelection;
private ArrayAdapter<CharSequence> featuresAdapter;
private List<CharSequence> featuresList;

创建:

featuresList = new ArrayList<CharSequence>();
featuresAdapter = new ArrayAdapter<CharSequence>(this,
  android.R.layout.simple_spinner_item, featuresList);
featuresAdapter.setDropDownViewResource(
  android.R.layout.simple_spinner_dropdown_item);
featuresSelection = ((Spinner) yourActivity.this
  .findViewById(R.id.locationSpinner));
featuresSelection.setAdapter(featuresAdapter);
featuresSelection.setOnItemSelectedListener(
  new MyOnItemSelectedListener());

一些功能(以编程方式向适配器添加东西)>

featuresAdapter.add("some string");

现在您有一个空的微调器,您可以编写代码以在为空时不打开对话框。或者他们可以反击。但您也可以在运行时使用函数或其他列表填充它。


也不需要 notifyDataSetChanged() 因为它应该默认设置为 true。
C
Cyril

我的 main.xml 上有一个微调器,它的 id 是 @+id/spinner1

这是我在 OnCreate 函数中写的:

spinner1 = (Spinner)this.findViewById(R.id.spinner1);
final String[] groupes = new String[] {"A", "B", "C", "D", "E", "F", "G", "H"};
ArrayAdapter<CharSequence> featuresAdapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, new ArrayList<CharSequence>());
featuresAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(featuresAdapter);
for (String s : groupes) featuresAdapter.add(s);

spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
     public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
         // Here go your instructions when the user chose something
         Toast.makeText(getBaseContext(), groupes[position], 0).show();
     }
     public void onNothingSelected(AdapterView<?> arg0) { }
});

它不需要类中的任何实现。


P
Peter Mortensen

我试过如下。拿一个按钮并给它点击事件。通过更改按钮背景,它似乎是一个微调器。

声明为全局变量 alertdialog 和默认值..

AlertDialog d;
static int default_value = 0;
final Button btn = (Button) findViewById(R.id.button1);
btn .setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v)
{
    //c.show();
    final CharSequence str[] = {"Android","Black Berry","Iphone"};
        AlertDialog.Builder builder =
          new AlertDialog.Builder(TestGalleryActivity.this).setSingleChoiceItems(
            str, default_value,new  DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int position)
            {
                Toast.makeText(TestGalleryActivity.this,
                               "" + position,
                               Toast.LENGTH_SHORT).show();
                default_value = position;
                btn.setText(str[position]);
                if(d.isShowing())
                    d.dismiss();
            }
        }).setTitle("Select Any");
        d = builder.create();
        d.show();
    }
});

N
Nimantha

此外,还有一个简单的技巧来显示默认值:

您可以在列表中添加默认值,然后使用 list.addAll(yourCollection); 添加所有集合

此处的示例可行代码:

List<FuelName> fuelList = new ArrayList<FuelName>();
                    fuelList.add(new FuelName(0,"Select One"));
                    fuelList.addAll(response.body());
                    ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, fuelList);
                    //fuelName.setPrompt("Select Fuel");
                    fuelName.setAdapter(adapter);

S
Sport

查看 iosched 应用程序,了解将元素添加到列表顶部的通用解决方案。特别是,如果您使用 CursorAdapter,请查看 TracksAdapter.java,它扩展了该定义以提供“setHasAllItem”方法和相关代码来管理列表计数以处理顶部的额外项目。

使用自定义适配器,您可以将文本设置为“选择一个”或您可能希望该顶部项目说的任何其他内容。


A
Alireza Sobhani

我为此找到了许多好的解决方案。大多数通过在适配器的末尾添加一个项目来工作,并且不显示下拉列表中的最后一个项目。对我来说最大的问题是微调器下拉列表将从列表底部开始。因此,在第一次触摸微调器后,用户会看到最后一个项目而不是第一个项目(如果有很多项目要显示)。

所以我把提示项放在列表的开头。并隐藏下拉列表中的第一项。

private void loadSpinner(){

    HintArrayAdapter hintAdapter = new HintArrayAdapter<String>(context, 0);

    hintAdapter.add("Hint to be displayed");
    hintAdapter.add("Item 1");
    hintAdapter.add("Item 2");
            .
            .
    hintAdapter.add("Item 30");

    spinner1.setAdapter(hintAdapter);

    //spinner1.setSelection(0); //display hint. Actually you can ignore it, because the default is already 0
    //spinner1.setSelection(0, false); //use this if don't want to onItemClick called for the hint

    spinner1.setOnItemSelectedListener(yourListener);
}

private class HintArrayAdapter<T> extends ArrayAdapter<T> {

    Context mContext;

    public HintArrayAdapter(Context context, int resource) {
        super(context, resource);
        this.mContext = context
    }

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(android.R.layout.simple_spinner_item, parent, false);
        TextView texview = (TextView) view.findViewById(android.R.id.text1);

        if(position == 0) {
            texview.setText("");
            texview.setHint(getItem(position).toString()); //"Hint to be displayed"
        } else {
            texview.setText(getItem(position).toString());
        }

        return view;
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view;

        if(position == 0){
            view = inflater.inflate(R.layout.spinner_hint_list_item_layout, parent, false); // Hide first row
        } else {
            view = inflater.inflate(android.R.layout.simple_spinner_dropdown_item, parent, false);
            TextView texview = (TextView) view.findViewById(android.R.id.text1);
            texview.setText(getItem(position).toString());
        } 

        return view;
    }
}

当 position 为 0 时,在 @Override getDropDownView() 中设置以下布局,以隐藏第一个提示行。

R.layout.spinner_hint_list_item_layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

</LinearLayout>

T
Tobias

我认为最简单的方法是在索引 0 上创建一个虚拟项目,说“选择一个”,然后在保存时检查选择是否不是 0。


查看项目列表怎么样?您想在顶部看到“选择一个”位置吗?这不仅仅是节省的问题。
@KrzysztofWolny Spinner 默认在位置 0 显示项目
w
wildnove

所以这是我最后一个按钮微调器的“全押”示例

在 activity_my_form.xml

    <Button
        android:id="@+id/btnSpinnerPlanets"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="left|center_vertical"
        android:singleLine="true"
        android:text="@string/selectAPlanet"
        android:textSize="10sp"
        android:background="@android:drawable/btn_dropdown">
    </Button>

在 strings.xml 中

<string name="selectAPlanet">Select planet&#8230;</string>

<string-array name="planets__entries">
    <item>The Sun with a name very long so long long long long longThe Sun with a name very long so long long long long longThe Sun with a name very long so long long long long long</item>
    <item>Mercury</item>
    <item>Venus</item>
    <item>Earth</item>
    <item>Mars</item>
    <item>Jupiter</item>
    <item>Saturn</item>
    <item>Uranus</item>
    <item>Neptune</item>
</string-array>

在 MyFormActivity.java

public class MyFormActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ((Button) findViewById(R.id.btnSpinnerPlanets)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final String[] items = view.getResources().getStringArray(R.array.planets__entries);
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(MyFormActivity.this, android.R.layout.simple_spinner_dropdown_item, items);
                new AlertDialog.Builder(MyFormActivity.this).setTitle("the prompt").setAdapter(adapter, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((Button) findViewById(R.id.btnSpinnerPlanets)).setText(items[which]);
                        dialog.dismiss();
                    }
                }).create().show();
            }
        });     

    }

}   

最后我得到了一个字体大小可配置的无第一项可选按钮微调器!!!感谢HRJ


C
Chapz

我为此找到的最佳解决方案实际上不是使用 Spinner,而是使用 AutoCompleteTextView。它基本上是一个带有 Spinner 的 EditText,用于在您键入时显示建议 - 但是,使用正确的配置,它可以完全按照 OP 的意愿行事等等。

XML:

<com.google.android.material.textfield.TextInputLayout
                android:id="@+id/item"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

            <androidx.appcompat.widget.AppCompatAutoCompleteTextView
                    android:id="@+id/input"
                    android:hint="Select one"
                    style="@style/AutoCompleteTextViewDropDown"/>
        </com.google.android.material.textfield.TextInputLayout>

风格:

<style name="AutoCompleteTextViewDropDown">
    <item name="android:clickable">false</item>
    <item name="android:cursorVisible">false</item>
    <item name="android:focusable">false</item>
    <item name="android:focusableInTouchMode">false</item>
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
</style>

至于适配器,请使用基本的 ArrayAdapter 或将其扩展为您自己的,但无需在适配器端进行额外的自定义。在 AutoCompleteTextView 上设置适配器。


A
Andrew Wyld

扩展 SpinnerAdapter 时,您会覆盖两个产生 View 的方法,getView(int, View, ViewGroup)getDropDownView(int, View, ViewGroup)。第一个提供插入到 Spinner 本身的 View;第二个提供下拉列表中的 View(顾名思义)。您可以覆盖 getView(...),以便在选择项目之前,它会显示一个包含提示的 TextView;然后,当您检测到某个项目已被选中时,您将其更改为显示与该项目相对应的 TextView

public class PromptingAdapter extends SpinnerAdapter {

    //... various code ...

    private boolean selectionmade = false;

    //call this method from the OnItemSelectedListener for your Spinner
    public setSelectionState(boolean b) {
        selectionmade = b;
    }

    @Override
    public View getView(int position, View recycle, ViewGroup container) {
        if(selectionmade) {
            //your existing code to supply a View for the Spinner
            //you could even put "return getDropDownView(position, recycle, container);"
        }
        else {
            View output;
            if(recycle instanceof TextView) {
                 output = recycle;
            }
            else {
                 output = new TextView();
                 //and layout stuff
            }
            output.setText(R.string.please_select_one);
            //put a string "please_select_one" in res/values/strings.xml
            return output;
        }
    }

//...
}

我发现了这种方法的一个缺陷:Spinner 会立即自动选择一个项目。我很快就会找到解决方法。
我说得太早了。然而,我并没有放弃。请注意,根据 Spinner 教程(据说在您选择了一个项目后会显示一个 Toast),这应该可以工作:developer.android.com/resources/tutorials/views/…
M
MPavlak

对于那些使用 Xamarin 的人,这里是与上面 aaronvargas 的答案等效的 C#。

using Android.Content;
using Android.Database;
using Android.Views;
using Android.Widget;
using Java.Lang;

namespace MyNamespace.Droid
{ 
  public class NothingSelectedSpinnerAdapter : BaseAdapter, ISpinnerAdapter, IListAdapter
  {
    protected static readonly int EXTRA = 1;
    protected ISpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, Context context) : this(spinnerAdapter, nothingSelectedLayout, -1, context)
    {
    }

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context)
    {
      this.adapter = spinnerAdapter;
      this.context = context;
      this.nothingSelectedLayout = nothingSelectedLayout;
      this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
      layoutInflater = LayoutInflater.From(context);
    }

    protected View GetNothingSelectedView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedLayout, parent, false);
    }

    protected View GetNothingSelectedDropdownView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedDropdownLayout, parent, false);
    }

    public override Object GetItem(int position)
    {
      return position == 0 ? null : adapter.GetItem(position - EXTRA);
    }

    public override long GetItemId(int position)
    {
      return position >= EXTRA ? adapter.GetItemId(position - EXTRA) : position - EXTRA;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
      // This provides the View for the Selected Item in the Spinner, not
      // the dropdown (unless dropdownView is not set).
      if (position == 0)
      {
        return GetNothingSelectedView(parent);
      }

      // Could re-use the convertView if possible.
      return this.adapter.GetView(position - EXTRA, null, parent);
    }

    public override int Count
    {
      get
      {
        int count = this.adapter.Count;
        return count == 0 ? 0 : count + EXTRA;
      }
    }

    public override View GetDropDownView(int position, View convertView, ViewGroup parent)
    {
      // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
      // Spinner does not support multiple view types
      if (position == 0)
      {
        return nothingSelectedDropdownLayout == -1 ?
          new View(context) :
          GetNothingSelectedDropdownView(parent);
      }

      // Could re-use the convertView if possible, use setTag...
      return adapter.GetDropDownView(position - EXTRA, null, parent);
    }

    public override int GetItemViewType(int position)
    {
      return 0;
    }

    public override int ViewTypeCount => 1;

    public override bool HasStableIds => this.adapter.HasStableIds;

    public override bool IsEmpty => this.adapter.IsEmpty;

    public override void RegisterDataSetObserver(DataSetObserver observer)
    {
      adapter.RegisterDataSetObserver(observer);
    }

    public override void UnregisterDataSetObserver(DataSetObserver observer)
    {
      adapter.UnregisterDataSetObserver(observer);
    }

    public override bool AreAllItemsEnabled()
    {
      return false;
    }

    public override bool IsEnabled(int position)
    {
      return position > 0;
    }
  }
}

S
Shravan Jain

我还使用以下代码解决了这个问题。假设您有一个项目列表,例如

ArrayList<Item> itemsArrayList = new ArrayList<Item>();
Item item1 = new Item();
item1.setId(1);
item1.setData("First Element");
Item item2 = new Item();
item2.setId(2);
Item2.setData("Second Element");
itemsArrayList.add(item1);
itemsArrayList.add(item2);

现在我们必须向微调器提供字符串,因为微调器无法理解对象。所以我们将创建一个带有这样的字符串项的新数组列表 ->

ArrayList<String> itemStringArrayList = new ArrayList<String>();
for(Item item : itemsArrayList) {
    itemStringArrayList.add(item.getData());
}

现在我们有 itemStringArrayList 包含两个字符串项的数组列表。我们必须将“选择项目”文本显示为第一项。所以我们必须在 itemStringArrayList 中插入一个新字符串。

itemStringArrayList.add("Select Item");

现在我们有一个数组列表 itemsArrayList,我们想在下拉列表中显示两个元素。但是这里的条件是......如果我们不选择任何东西,那么 Select Item 应该作为第一个元素出现,它将不会被启用。

所以我们可以像这样实现这个功能。如果您需要将数组列表项加载到 android 微调器中。所以你将不得不使用一些适配器。所以在这里我将使用ArrayAdapter。我们也可以使用自定义适配器。

ArrayAdapter<String> itemsArrayAdapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.spinner_item, itemsArrayList){
        @Override
        public boolean isEnabled(int position) {
            if(position == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        @Override
        public View getDropDownView(int position, View convertView,
                                    ViewGroup parent) {
            View view = super.getDropDownView(position, convertView, parent);
            TextView tv = (TextView) view;
            if(position == 0){
                // Set the hint text color gray
                tv.setTextColor(Color.GRAY);
            }
            else {
                tv.setTextColor(Color.BLACK);
            }
            return view;
        }
    };

itemsArrayAdapter.setDropDownViewResource(R.layout.spinner_item);
your_spinner_name.setAdapter(itemsArrayAdapter);

在这段代码中。我们正在使用自定义微调器布局,即 R.layout.spinner_item。这是一个简单的文本视图

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:textStyle="italic"
    android:fontFamily="sans-serif-medium"
    />

我们需要禁用微调器中的第一个文本。所以对于位置 0,我们禁用文本。我们也可以通过覆盖 getDropDownView 方法来设置颜色。所以通过这种方式,我们将得到预期的微调器。


p
pfaehlfd

我昨天遇到了同样的问题,不想向 ArrayAdapter 添加隐藏项或使用反射,这工作正常但有点脏。

在阅读了许多帖子并尝试之后,我通过扩展 ArrayAdapter 和覆盖 getView 方法找到了解决方案。

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

/**
 * A SpinnerAdapter which does not show the value of the initial selection initially,
 * but an initialText.
 * To use the spinner with initial selection instead call notifyDataSetChanged().
 */
public class SpinnerAdapterWithInitialText<T> extends ArrayAdapter<T> {

    private Context context;
    private int resource;

    private boolean initialTextWasShown = false;
    private String initialText = "Please select";

    /**
     * Constructor
     *
     * @param context The current context.
     * @param resource The resource ID for a layout file containing a TextView to use when
     *                 instantiating views.
     * @param objects The objects to represent in the ListView.
     */
    public SpinnerAdapterWithInitialText(@NonNull Context context, int resource, @NonNull T[] objects) {
        super(context, resource, objects);
        this.context = context;
        this.resource = resource;
    }

    /**
     * Returns whether the user has selected a spinner item, or if still the initial text is shown.
     * @param spinner The spinner the SpinnerAdapterWithInitialText is assigned to.
     * @return true if the user has selected a spinner item, false if not.
     */
    public boolean selectionMade(Spinner spinner) {
        return !((TextView)spinner.getSelectedView()).getText().toString().equals(initialText);
    }

    /**
     * Returns a TextView with the initialText the first time getView is called.
     * So the Spinner has an initialText which does not represent the selected item.
     * To use the spinner with initial selection instead call notifyDataSetChanged(),
     * after assigning the SpinnerAdapterWithInitialText.
     */
    @Override
    public View getView(int position, View recycle, ViewGroup container) {
        if(initialTextWasShown) {
            return super.getView(position, recycle, container);
        } else {
            initialTextWasShown = true;
            LayoutInflater inflater = LayoutInflater.from(context);
            final View view = inflater.inflate(resource, container, false);

            ((TextView) view).setText(initialText);

            return view;
        }
    }
}

Android 在初始化 Spinner 时所做的是,在为 T[] objects 中的所有项目调用 getView 之前为所选项目调用 getView。 SpinnerAdapterWithInitialText 在第一次调用时返回带有 initialTextTextView。所有其他时间它调用 super.getView,这是 ArrayAdaptergetView 方法,如果您正常使用 Spinner,则会调用该方法。

要查明用户是否选择了微调器项目,或者微调器是否仍显示 initialText,请调用 selectionMade 并交出分配给适配器的微调器。


s
stephane k.

如果您只有三个选择,我只会使用带有 RadioButtons 的 RadioGroup,您可以首先将它们全部取消选中。


J
Jed

以前提交的答案都没有真正按照我想要解决这个问题的方式工作。对我来说,理想的解决方案是在微调器首次显示时提供“选择一个”(或任何初始文本)。当用户点击微调器时,初始文本不应该是显示的下拉列表的一部分。

为了使我的特殊情况更加复杂,我的微调器数据来自通过 LoaderManager 回调加载的游标。

经过大量实验,我想出了以下解决方案:

public class MyFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>{

private static final String SPINNER_INIT_VALUE = "Select A Widget";
private Spinner mSpinner;
private int mSpinnerPosition;
private boolean mSpinnerDropDownShowing = false;
private View mSpinnerDropDown;

private MyCursorAdapter mCursorAdapter;

...

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
...

mCursorAdapter = new MyCursorAdapter(getActivity());

mSpinner = (Spinner) rootView.findViewById(R.id.theSpinner);
mSpinner.setOnTouchListener(mSpinnerTouchListener);
mSpinner.setAdapter(mCursorAdapter);

...
}

//Capture the touch events to toggle the spinner's dropdown visibility
private OnTouchListener mSpinnerTouchListener = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if(mSpinnerDropDown != null && mSpinnerDropDownShowing == false){
            mSpinnerDropDownShowing = true;
            mSpinnerDropDown.setVisibility(View.VISIBLE);
        }
        return false;
    }
};

//Capture the click event on the spinner drop down items
protected OnClickListener spinnerItemClick = new OnClickListener(){

    @Override
    public void onClick(View view) {
        String widget = ((TextView) view.findViewById(android.R.id.text1)).getText().toString();

        if(!widget.equals(SPINNER_INIT_VALUE)){
            if(mCursorAdapter != null){
                Cursor cursor = mCursorAdapter.getCursor();
                if(cursor.moveToFirst()){
                    while(!cursor.isAfterLast()){
                        if(widget.equals(cursor.getString(WidgetQuery.WIDGET_NAME))){

                            ...

                            //Set the spinner to the correct item
                            mSpinnerPosition = cursor.getPosition() + 1;
                            mSpinner.setSelection(mSpinnerPosition);
                            break;
                        }
                        cursor.moveToNext();
                    }
                }
            }
        }

        //Hide the drop down. Not the most elegent solution but it is the only way I could hide/dismiss the drop down
        mSpinnerDropDown = view.getRootView();
        mSpinnerDropDownShowing = false;
        mSpinnerDropDown.setVisibility(View.GONE);
    }
};

private class MyCursorAdapter extends CursorAdapter {

    private final int DISPLACEMENT = 1;
    private final int DEFAULT_ITEM_ID = Integer.MAX_VALUE;

    private Activity mActivity;

    public MyCursorAdapter(Activity activity) {
            super(activity, null, false);
            mActivity = activity;
    }

    //When loading the regular views, inject the defualt item
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(position == 0){
            if(convertView == null){
                convertView = mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
            }
            return getDefaultItem(convertView);
        }
        return super.getView(position - DISPLACEMENT, convertView, parent);
    }

    //When loading the drop down views, set the onClickListener for each view
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent){
        View view = super.getDropDownView(position, convertView, parent);
        view.setOnClickListener(spinnerItemClick);
        return view;
    }

    //The special default item that is being injected
    private View getDefaultItem(View convertView){
        TextView text = (TextView) convertView.findViewById(android.R.id.text1);
        text.setText(SPINNER_INIT_VALUE);
        return convertView;
    }

    @Override
    public long getItemId(int position) {
        if (position == 0) {
            return DEFAULT_ITEM_ID;
        }
        return super.getItemId(position - DISPLACEMENT);
    }

    @Override
    public boolean isEnabled(int position) {
        return position == 0 ? true : super.isEnabled(position - DISPLACEMENT);
    }

    @Override
    public int getViewTypeCount() {
        return super.getViewTypeCount() + DISPLACEMENT;
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return super.getViewTypeCount();
        }

        return super.getItemViewType(position - DISPLACEMENT);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor){

        if(cursor.isAfterLast()){
            return;
        }

        TextView text = (TextView) view.findViewById(android.R.id.text1);
        String WidgetName = cursor.getString(WidgetQuery.WIDGET_NAME);
        text.setText(WidgetName);
    }
}
}

S
SBerg413

我通过使用按钮而不是 Spinner 来处理这个问题。 I have the sample project up on GitHub.

在项目中,我同时显示 Spinner 和按钮,以表明它们确实看起来相同。除了按钮,您可以将初始文本设置为您想要的任何内容。

这是活动的样子:

package com.stevebergamini.spinnerbutton;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Spinner;

public class MainActivity extends Activity {

    Spinner spinner1;
    Button button1;
    AlertDialog ad;
    String[] countries;

    int selected = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        spinner1 = (Spinner) findViewById(R.id.spinner1);
        button1 = (Button) findViewById(R.id.button1);

        countries = getResources().getStringArray(R.array.country_names);

        //  You can also use an adapter for the allert dialog if you'd like
        //  ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, countries);        

        ad = new AlertDialog.Builder(MainActivity.this).setSingleChoiceItems(countries, selected,  
                new  DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            button1.setText(countries[which]);
                            selected = which;
                            ad.dismiss();

                        }}).setTitle(R.string.select_country).create(); 


        button1.setOnClickListener( new OnClickListener(){

            @Override
            public void onClick(View v) {
                ad.getListView().setSelection(selected);
                ad.show();              
            }});

    }

}

注意:是的,我意识到这取决于应用的主题,如果使用 Theme.Holo,外观会略有不同。但是,如果您使用的是 Theme.Black 等传统主题之一,那么您就可以开始使用了。


C
Claudio Ferraro

似乎是一个平庸的解决方案,但我通常只是在微调器的前面放一个 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的背景颜色应该和Spinner一样。适用于 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) {
        }

    });

R
Rako

对我来说,它的工作原理是这样的。具有仅更改某些选项中的文本的改进,而不是全部更改。

首先,我取微调器的名称并使用自定义视图创建 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);
    }

C
Community

请参阅上述答案之一:https://stackoverflow.com/a/23005376/1312796

我添加了我的代码来修复一个小错误。没有检索到数据的地方..如何显示提示文本..!

这是我的技巧……它对我很有效。 !

尝试将微调器放在 Relative_layout 中并将 Textview 与微调器对齐,并在微调器的适配器加载或空时使用 Textview 的可见性(显示/隐藏)。像这样:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:background="#ededed"
android:orientation="vertical">



    <TextView
        android:id="@+id/txt_prompt_from"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:textColor="@color/gray"
        android:textSize="16sp"
        android:layout_alignStart="@+id/sp_from"
        android:text="From"
        android:visibility="gone"/>

    <Spinner
        android:id="@+id/sp_from"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        />

这是代码:

  txt__from = (TextView) rootView.findViewById(R.id.txt_prompt_from);

在微调器适配器加载和清空之前和之前调用此方法。

setPromptTextViewVisibility (); //True or fales 

public void setPromptTextViewVisibility (boolean visible )
{
    if (visible)
    {
        txt_from.setVisibility(View.VISIBLE);
    }
    else
    {
        txt_from.setVisibility(View.INVISIBLE);
    }

}