Android Spinner'da bir öğe nasıl gizlenir


101

Bir Android spinner widget'ında bir öğeyi gizlemenin bir yolunu arıyorum. Bu, hiçbir öğe seçilmemiş bir döndürücüyü simüle etmenize olanak tanır ve seçilen her öğe için her zaman onItemSelected () geri çağrısının çağrılmasını sağlar (gizli öğe "geçerli" öğe ise). Normalde çarkta her zaman bir geri arama oluşturmayan bir öğe vardır, yani mevcut olan.

Stackoverflow'da öğelerin nasıl devre dışı bırakılacağına (grileştirileceğine) ilişkin bazı kodlar vardır, ancak öğeler yokmuş gibi nasıl tamamen gizleneceği yoktur.

Uzun deneyimlerden sonra, çeşitli eski ve yeni Android platformlarında çalışan biraz hack-ish bir çözüm buldum. Fark edilmesi zor bazı küçük kozmetik dezavantajları vardır. Yine de "bunu bir iplikçiyle yapma" dışında daha resmi bir çözüm duymak istiyorum.

Bu her zaman çarktaki ilk öğeyi gizler, ancak keyfi bir öğeyi veya birden fazla öğeyi gizlemek için oldukça kolay bir şekilde genişletilebilir. Döndürücü öğeler listenizin başına boş bir dizi içeren sahte bir öğe ekleyin. Döndürücü diyalogu açılmadan önce mevcut döndürücü seçimini öğe 0'a ayarlamak isteyebilirsiniz, bu, seçilmemiş bir döndürücüyü simüle edecektir.

ArrayAdapter yöntemi geçersiz kılma ile Spinner kurulum örneği:

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

diğer ağlarda ne buldunuz? şimdiye kadar ne denedin?
dldnh

Üzgünüm lah, nasıl yapacağımı bilmiyorum.
Louisth

Güzel çözüm! Ama tv.setVisibility(View.GONE);hattın gereksiz olduğunu düşünüyorum . Yorum yapmak, en azından Android 4.4.2 / KitKit'te (bir LG / Google Nexus 4'te) herhangi bir (görsel) fark yaratmıyor gibi görünüyor.
Matthias

Bu sorunun cevabı gayet iyi çalışıyor ..
Rat-a-tat-a-tat Ratatouille

Bu bir gelişme olmayabilir, ancak setTag(1)textView'de 0 konumunda kullandım, daha sonra convertView.getTag() != nullyeniden kullanılan görünümün 0 konumu için oluşturulan 0 yükseklik görünümü mü yoksa diğer dönen öğeler için kullanılan normal bir görünüm mü olduğunu belirlemek için kullandım. Bu, super.getDropDownView(position, convertView, parent)daima yeni bir görünüm oluşturmak yerine bazen kullanabilmem için oldu .
Daniel Handojo

Yanıtlar:


50

Rasgele bir öğeyi veya birden fazla öğeyi gizlemek için, kendi adaptörünüzü uygulayabileceğinizi ve gizlemek istediğiniz dizini (veya dizin dizilerini) ayarlayabileceğinizi düşünüyorum.

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

Ve öğe listesini oluştururken özel adaptörünüzü kullanın.

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

(Kodu test etmedim) umarım yardımcı olur.


1
Bu bir çözüm değil. Sorunun güncellenmesi doğru kodu sağlar.
dldnh

13
Tv.setHeight (0) olmadan, TextView hala görülebilir.
v4r

merhaba, bu kodu çeviricimdeki ilk öğeyi gizlemek için kullandım, iyi çalışıyor, döndürücüm bana ikinci öğeyi gösterecek, ancak bu ikinci öğeyi tıkladığımda, o öğenin üzerindeki metin, döndürücüm olarak ayarlanacak, i o öğeye tıkladığımda döndürücümde herhangi bir metin göstermek istemiyorum, lütfen bana yol göster?
Achin

1
Müthiş :) Basit çözüm :)
Chaitanya

1
Tıkır tıkır çalışıyor..!
Krupa Kakkad

20

Listeyi kısaltarak listenin sonundaki bir öğeyi gizlemek daha kolaydır.

Ama önce onu seçmeli ve böylece çarkta görünecek ve ardından seçimin görüntülenen öğelerden birine değiştirilip değiştirilmediğini kontrol etmelisiniz.

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
Temiz bir yaklaşım bulmak için yarım saat arıyordum ve bu açık ara en iyi yaklaşım. Sadece listeyi kısaltın, ancak öğe gerçekten var. Mükemmel.
KSdev

1
Bu, Lollipop'ta işe yaramıyor gibi görünüyor, [Birini seçin] testi başlangıçta Spinner'da görünmüyor. Eski Android sürümlerindeki aynı kod, hepimizin istediğini yapıyor gibi görünüyor.
Jonathan Caryl

1
Döndürücü metni, yön değişiminde, eğiriciye dokunulmasa bile "Dize3" olarak değiştirilir. @Romich
Yksh

herhangi biri soruma bakabilir mi?
Moeez

5

Döndürücü açılır listesindeki herhangi bir öğeyi gizlemek için, gerekli kriterlere göre gizlenmesi gereken öğenin konumunu geçmeniz gerekir. Bunu, açılır menüden seçilen öğeyi gizleme durumunda başardım

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

Ve adaptörün ayarlanması bunun gibi bir şey

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

Açılır menüden bazı öğeler seçildiğinde konumun da değiştirilmesi gerekir

 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

Sırf ilgi için, "Sor" u ipucu olarak kullanmak için bir çözüm geliştirdim. Bu kod için yapılmıştır Xamarin.Android, ancak 10 dakika içinde mükemmel bir şekilde Java'ya taşınabilir. ArrayAdapterKaynak diziye 0 dizinli veya endeksli öğeler eklemeden basit bir şekilde kullanın . Ayrıca SpinnerGeolocation.SelectedItemId, hiçbir şey seçilmediğinde de -1'e ayarlanır ( hintmevcut öğedir).

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

herhangi biri soruma bakabilir mi?
Moeez

1

Sorunumu çözen bu çözümü buldum.

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 yerine Dizi Listesine doğrulama koymanın daha iyi olacağını düşünüyorum çünkü öğe filtrelendikten sonra Spinner'a eklemek güvenli olacak


0

Benim için en çok işe yarayan başka bir yaklaşım, yeni bir boş görünüm nesnesi döndürmektir. Dizi öğeleriyle oynamadığınız için bu oldukça temiz bir yaklaşımdır.

Adaptör sınıfınızı genişletme oluşturun ArrayAdapter

yönteminin içinde

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

Bu çok eski bir soru, ancak ilk öğeleri de göstermemek için güzel (ve muhtemelen) temiz bir yol buldum. @ Romich'in cevabından esinlenerek, ilk maddeyi / maddeleri atlamak için benzer bir mantık ekledim.

Bu, rastgele sayıda öğeyi etkili bir şekilde gizler (varsayılan olarak 1). Kod, yalnızca oluşturulacak nesnelerin boyutunun gerçekte olduğundan daha kısa olduğunu bildirir ve ayrıca oluşturulacak öğelerin dizinini değiştirir, böylece rastgele öğe sayısını atlarız.

İşleri basit tutmak için, şu anda kullandığım, rastgele öğelerin gizlenme listesini destekleyen, ancak kodda birkaç ince ayar ile kolayca yönetilebilen çözümü hariç tuttum.

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)
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.