如何在Android Spinner中隐藏一项


101

我正在寻找一种在Android微调器小部件中隐藏一个项目的方法。这将允许您模拟不选择任何项目的微调器,并确保始终为选中的每个项目调用onItemSelected()回调(如果隐藏的项目是“当前”项目)。通常,微调器中总是有一个不产生回调的项,即当前项。

在stackoverflow上有一些代码说明如何禁用(变灰)项目,但没有如何完全隐藏项目(好像它们不存在一样)。

经过大量的试验,我提出了一种有点hack-ish的解决方案,该解决方案可以在各种新旧Android平台上使用。它具有一些较小的外观缺陷,很难注意到。除了“不要用微调器做到这一点”之外,我还是想听听更正式的解决方案。

这始终会隐藏微调器中的第一个项目,但是可以很容易地扩展为隐藏任意项目或多个项目。在微调器项目列表的开头添加一个包含空字符串的虚拟项目。您可能需要在打开微调器对话框之前将当前微调器选择设置为项目0,这将模拟未选择的微调器。

带有ArrayAdapter方法的Spinner安装示例覆盖:

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

// Populate the spinner using a customized ArrayAdapter that hides the first (dummy) entry
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list) {
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent)
    {
        View v = null;

        // If this is the initial dummy entry, make it hidden
        if (position == 0) {
            TextView tv = new TextView(getContext());
            tv.setHeight(0);
            tv.setVisibility(View.GONE);
            v = tv;
        }
        else {
            // Pass convertView as null to prevent reuse of special case views
            v = super.getDropDownView(position, null, parent);
        }

        // Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling 
        parent.setVerticalScrollBarEnabled(false);
        return v;
    }
};

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

您在其他互连网上发现了什么?你都尝试了些什么?
dldnh 2012年

对不起,我不知道该怎么办。
路易丝

不错的解决方案!但是我认为这tv.setVisibility(View.GONE);行是不必要的。至少在Android 4.4.2 / KitKit(在LG / Google Nexus 4上)上,注释掉似乎并没有任何(视觉上的)差异。
Matthias 2014年

这个问题的答案很好..
Rat-a-tat-a-tat Ratatouille 2014年

这可能不是一个改进,但是我setTag(1)在textView的位置0上使用过,然后用来convertView.getTag() != null确定重用的视图是为位置0创建的0高度视图还是用于其他微调器项目的普通视图。这样一来,我super.getDropDownView(position, convertView, parent)有时可以使用而不是总是创建一个新视图。
Daniel Handojo

Answers:


49

要隐藏任意一项或多项,我认为您可以实现自己的适配器并设置要隐藏的索引(或索引数组列表)。

public class CustomAdapter extends ArrayAdapter<String> {

     private int hidingItemIndex;

     public CustomAdapter(Context context, int textViewResourceId, String[] objects, int hidingItemIndex) {
         super(context, textViewResourceId, objects);
         this.hidingItemIndex = hidingItemIndex;
     }

     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         View v = null;
         if (position == hidingItemIndex) {
             TextView tv = new TextView(getContext());
             tv.setVisibility(View.GONE);
             v = tv;
         } else {
             v = super.getDropDownView(position, null, parent);
         }
         return v;
     }
 }

在创建项目列表时,请使用自定义适配器。

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

int hidingItemIndex = 0;

CustomAdapter dataAdapter = new CustomAdapter(this, android.R.layout.simple_spinner_item, list, hidingItemIndex);

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

(我尚未测试代码)希望有帮助。


1
这不是解决方案。问题的更新提供了正确的代码。
dldnh

13
没有tv.setHeight(0),TextView仍然可见。
v4r

嗨,我已经使用此代码隐藏了微调器中的第一个项目,它工作正常,微调器将向我显示第二个项目,但是当我单击第二个项目时,该项目上的文本将设置为我的微调器,我当我单击该项目时,不想在微调框上显示任何文本,请指导我?
阿钦(Achin)2014年

1
太棒了:)简单的解决方法:)
柴坦亚岛2014年

1
奇迹般有效..!
Krupa Kakkad

20

通过截断列表可以更轻松地在列表末尾隐藏项目。

但是您必须先选择它,以便它出现在微调器中,然后检查选择是否已更改为显示的项目之一。

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

3
我搜索了一个半小时,试图找到一种干净的方法,这是迄今为止最好的方法。只是截断列表,但该项目实际上存在。优秀的。
KSdev 2015年

1
这似乎在Lollipop中不起作用,[Select one]测试最初并未出现在Spinner中。较旧的Android版本上的相同代码似乎确实可以满足我们的所有要求。
乔纳森·卡里尔

1
即使未触摸微调器,微调器文本也会在方向更改时更改为“ String3”。@Romich
Yksh

有人可以调查我的问题吗?
Moeez '17

5

要隐藏微调框下拉菜单中的任何项目,您需要根据所需条件传递需要隐藏的项目的位置。我在隐藏从下拉列表中选择的项目的用例中实现了这一点

public class CustomAdapter extends ArrayAdapter<String> {

private List<String> dates;
private int hideItemPostion;

public CustomAdapter (Context context, int resource, List<String> dates) {
    super(context, resource,dates);
    this.dates=dates;
}
public void setItemToHide(int itemToHide)
{
    this.hideItemPostion =itemToHide;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    View v = null;
    if (position == hideItemPostion) {
        TextView tv = new TextView(getContext());
        tv.setVisibility(View.GONE);
        tv.setHeight(0);
        v = tv;
        v.setVisibility(View.GONE);
    }
    else
        v = super.getDropDownView(position, null, parent);
    return v;
}}

设置适配器是这样的

final CustomAdapter dataAdapter = new CustomAdapter(this,R.layout.spinner_item,dates);
    dataAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
    spinner.setAdapter(dataAdapter);
    dataAdapter.setItemToHide(0);

从下拉菜单中选择一些项目后,位置也需要更改

 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, final int i, long l) {
        dataAdapter.notifyDataSetChanged();
            mEPGDateSelector.setSelection(i);
            dataAdapter.setItemToHide(i);}

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

        }
    });

1

出于兴趣,我提出了一个使用“提示”作为提示的解决方案。这段代码是为制作的Xamarin.Android,但可以在10分钟内完美移植到Java。ArrayAdapter无需添加0索引或计数索引项到源数组,就可以简单地使用它。SpinnerGeolocation.SelectedItemId如果什么也没有选择(hint当前项),则它也设置为-1 。

public class ArrayAdapterWithHint<T>: ArrayAdapter<T>
{
    protected bool HintIsSet = false;
    protected int HintResource = 0;

    public ArrayAdapterWithHint(Context context, int textViewResourceId,
                   T[] objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                   int textViewResourceId, T[] objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }
    public ArrayAdapterWithHint(Context context, int textViewResourceId,
             IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                    int textViewResourceId, IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }

    public override View GetDropDownView(int position, View convertView,
                ViewGroup parent)
    {
        if (HintIsSet)
            return base.GetDropDownView(position + 1,
                               convertView, parent);
        return base.GetDropDownView(position, convertView, parent);
    }

    public override View GetView(int position, View convertView,
                      ViewGroup parent)
    {
        if (!HintIsSet && parent is Spinner && 
                    !string.IsNullOrWhiteSpace((parent as Spinner).Prompt))
        {
            Insert((parent as Spinner).Prompt, 0);
            HintIsSet = true;
            (parent as Spinner).SetSelection(base.Count - 1);
        }
        if (HintIsSet && position >= base.Count - 1)
        {
            View hintView = base.GetView(0, convertView, parent);
            if (hintView is TextView)
                (hintView as TextView).SetTextAppearance(
                                                     Context, HintResource);
            return hintView;
        }
        if (HintIsSet && position < base.Count - 1)
            return base.GetView(position + 1, convertView, parent);
        return base.GetView(position, convertView, parent);
    }

    public override long GetItemId(int position)
    {
        if (HintIsSet)
        {
            if (position >= base.Count - 1)
                return -1;
            return position;
        }
        return base.GetItemId(position);
    }

    public override int Count
    {
        get
        {
            return base.Count > 0 && HintIsSet ? base.Count - 1 : base.Count;
        }
    }
}

有人可以调查我的问题吗?
Moeez '17

1

我找到了解决我问题的解决方案。

final Spinner mySpinner = (Spinner)findViewById(R.id.spinner_triptype);

   final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.spinner_item, R.id.weekofday, triptype_initial);

   final ArrayAdapter<String> adapter_temp = new ArrayAdapter<String>
(this,R.layout.spinner_item, R.id.weekofday, triptype_array);


   mySpinner.setAdapter(adapter);
    mySpinner.setOnTouchListener(new View.OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
       // display your error popup here
        if(flag_spinner_isFirst){
           mySpinner.setAdapter(adapter_temp);
           flag_spinner_isFirst = false;
          }
           v.onTouchEvent(event);
           return true;

       }
    });

0

我认为最好将验证放在“数组列表”上而不是在Spinner上,因为一旦过滤了该项,就可以安全地添加到Spinner中


0

对我来说最有效的另一种方法是返回一个新的空白视图对象。由于您不使用数组元素,因此这是一种非常干净的方法。

创建扩展的适配器类 ArrayAdapter

在你的方法里面

public View getView(int position, View convertView, ViewGroup parent) {
    View row = getCustomView();
    if(position==0) // put the desired check here.
         {
            row  = new View(context);
         }
    }
    return row;
}

0

这是一个非常老的问题,但是我发现了一种不错的(并且很可能是)干净的方式来不显示第一项。受@Romich答案的启发,我添加了类似的逻辑来跳过第一项。

这有效地隐藏了任意数量的项目(默认为1)。该代码仅报告要渲染的对象的大小,使其小于实际大小,并且还更改了要渲染的项目的索引,因此我们跳过了任意数量的项目。

为简单起见,我排除了当前使用的解决方案,该解决方案支持隐藏随机项目列表,但是只需对代码进行一些调整即可轻松解决。

class ArrayAdapterCustom(context: Context, textViewResourceId: Int, vararg objects: String)
    : ArrayAdapter<String>(context, textViewResourceId, objects) {

    //Can skip first n items (skip 1 as default)
    var hideFirstItemsCount = 1

    override fun getCount(): Int {
        return super.getCount() - hideFirstItemsCount
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        return super.getDropDownView(position + hideFirstItemsCount, convertView, parent)
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.