Android Spinnerで1つのアイテムを非表示にする方法


101

Androidスピナーウィジェットで1つのアイテムを非表示にする方法を探しています。これにより、アイテムが選択されていない状態でスピナーをシミュレートでき、選択されたすべてのアイテムに対して常にonItemSelected()コールバックが確実に呼び出されます(非表示のアイテムが「現在の」アイテムである場合)。通常、スピナーには常に、コールバックを生成しない1つの項目、つまり現在の項目があります。

アイテムを無効にする(グレー表示する)方法については、stackoverflowにコードがいくつかありますが、アイテムが存在しないかのように完全に非表示にする方法はありません。

多くの実験の後、私はさまざまな新旧のAndroidプラットフォームで動作する、ややハックっぽいソリューションを思いつきました。それには気づきにくいいくつかの小さな化粧品の欠点があります。「スピナーでそれをしないでください」以外の、より公式な解決策についてはまだ聞きたいです。

これは常にスピナーの最初のアイテムを非表示にしますが、任意のアイテムまたは複数のアイテムを非表示にするようにかなり簡単に拡張できます。スピナーアイテムのリストの先頭に、空の文字列を含むダミーアイテムを追加します。スピナーダイアログが開く前に、現在のスピナー選択をアイテム0に設定すると、選択されていないスピナーがシミュレートされます。

ArrayAdapterメソッドをオーバーライドしたスピナーのセットアップ例:

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年

すみません、方法がわかりません。
ルイス、2013

素敵な解決策!でもtv.setVisibility(View.GONE);ラインは不要だと思います。コメントアウトしても、少なくともAndroid 4.4.2 / KitKit(LG / Google Nexus 4)では、(視覚的な)違いはないようです。
Matthias

この問題の答えは...うまく機能
ラット-TAT-TATレミーのおいしいレストラン

これは改善さsetTag(1)れないかもしれませんが、textViewで位置0を使用してconvertView.getTag() != nullから、再利用されたビューが位置0で作成された高さ0のビューか、他のスピナーアイテムで使用される通常のビューかを判断しました。これはsuper.getDropDownView(position, convertView, parent)、常に新しいビューを作成する代わりに、時々使用できるようにするためでした。
Daniel Handojo 16

回答:


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 2014

こんにちは、このコードを使用して、スピナーの最初のアイテムを非表示にしました。これは正常に機能します。スピナーには2番目のアイテムが表示されますが、2番目のアイテムをクリックすると、そのアイテムのテキストがスピナーに設定されます。そのアイテムをクリックしたときにスピナーにテキストを表示したくない場合は、私をガイドしてください。
Achin

1
素晴らしい:)シンプルなソリューション:)
チャイタンヤ

1
魅力のように動作します。
Krupa Kakkad

20

リストを切り捨てることで、リストの最後にあるアイテムを非表示にする方が簡単です。

ただし、最初にそれを選択してスピナーに表示する必要があります。次に、選択が表示されている項目の1つに変更されているかどうかを確認します。

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
私はクリーンなアプローチを見つけるために30分を探していました、そしてこれは断然最良のアプローチです。リストを切り捨てるだけで、アイテムは実際に存在します。優れた。
KSdev 2015年

1
これはLollipopでは機能しないようです。[1つ選択]テストは最初はSpinnerに表示されません。古いAndroidバージョンの同じコードは、私たち全員が望むことを実行するようです。
ジョナサンキャリル2015年

1
スピナーが触れられていなくても、方向が変わるとスピナーテキストが「String3」に変更されます。@Romich
Yksh

誰でも私の質問を調べることができますか?
Moeez 2017

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インデックスまたはcountインデックスの項目を追加せずに、単純なように使用します。また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 2017

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よりもArray Listで検証を行う方が良いと思います。


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)
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.