Android Spinner: Başlatma sırasında onItemSelected aramalarından kaçının


157

A Spinnerve a ile bir Android uygulaması oluşturdum TextView. TextView'deki Spinner açılır listesinden seçilen öğeyi görüntülemek istiyorum. Spinner'ı onCreateyöntemde uyguladım, böylece programı çalıştırdığımda, TextView(açılır listeden bir öğe seçmeden önce) bir değer gösterir .

TextView değerini yalnızca açılır listeden bir öğe seçtikten sonra göstermek istiyorum. Bunu nasıl yaparım?

İşte benim kod:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

public class GPACal01Activity extends Activity implements OnItemSelectedListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Spinner spinner = (Spinner) findViewById(R.id.noOfSubjects);

        // Create an ArrayAdapter using the string array and a default spinner layout
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.noofsubjects_array, android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // Apply the adapter to the spinner
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);
    }

    public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
        TextView textView = (TextView) findViewById(R.id.textView1);
        String str = (String) parent.getItemAtPosition(pos);
        textView.setText(str);
    }

    public void onNothingSelected(AdapterView<?> arg0) {
        // TODO Auto-generated method stub

    }
}

eğiriciler her zaman varsayılan olarak seçilen bir değere sahiptir, varsayılan olarak seçilen değeri olmayan bir döndürücüye sahip olmak istiyorsanız, özel döndürücünüzü oluşturmalı veya boş bir girişle özel bir döndürücü oluşturmalısınız ve getView () yönteminde, Ham düzeni GONE
Houcine

5
Nasıl böyle sinir bozucu bir hata 2018 sonunda hala var ???
user-123

Yanıtlar:


174
spinner.setOnItemSelectedListener(this); // Will call onItemSelected() Listener.

Yani bunu ilk kez herhangi bir Tamsayı değeri ile ele alın

Örnek: Başlangıçta atın int check = 0;

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
   if(++check > 1) {
      TextView textView = (TextView) findViewById(R.id.textView1);
      String str = (String) parent.getItemAtPosition(pos);
      textView.setText(str);
   }
}

Bunu, boole değeriyle ve ayrıca geçerli ve önceki konumları kontrol ederek yapabilirsiniz. Buraya bakın


2
Korku veren adam ... ilk kez bu sorunla karşı karşıya kaldım ben özel spinner uygulamak çalıştı ... işe yaramadı ... ama çözüm bir cazibe gibi çalıştı ... teşekkürler.
Sash_KP

1
Nerede çek beyan ediyorsunuz? GetView () dışında mı? Görünümün içinde mi? Nerede? çözümünü denedim ama benim için çalışmıyor.
user3718908

10
onun bir yama değil bir çözüm sanırım.
saksham

1
Ben de aynı problemle karşı karşıyayım. Bir tür böcek mi? aynı öğeyi tekrar tekrar seçersem, dinleyici ilk kez çalışmaz. Yalnızca seçim öğesi değiştiğinde çalışır. Herhangi bir yorum, yardım?
amitava

1
Bu sorunu aynı sorunumla denedim, ancak bu sadece bir tane uyandırıyor, örneğin: Açılırken 2 öğe bulduğumda, herhangi bir spinner öğesini 1. kez seçtiğimde, 2. kez denediğimde çalışır, düzgün çalışmıyor
Waseem

117

OnItemSelectedListener'ı ayarlamadan önce bu satırı koymanız yeterli

spinner.setSelection(0,false)

7
Bunun nasıl yardımcı olduğunu ve nedenini yazmanız daha iyi bir yanıt olacaktır.
user3533716

1
Yardımcı olur, ama nasıl?
AEMLoviji

14
Bu, önce seçimi ayarlayıp ardından bir dinleyici eklediğiniz için çalışır, ancak daha önce bu seçimi zaten seçtiğiniz için dinleyici çağrılmaz. Dinleyiciyi yalnızca yeni seçimler çağıracaktır.
android geliştirici

4
Bu , dahili setSelection(int, boolean)aramalar nedeniyle çalışır setSelectionInt()ve bunu çağırdıktan sonra (önce değil) dinleyiciyi ayarlamanız gerekir. setSelection(int)Bunun işe yaramayacağına dikkat edin , çünkü setNextSelectedPositionInt()dahili olarak çağırıyor ve beni buraya getiren şey bu.
Hai Zhang

3
OnCreateView () sırasında veya öncesinde bildirilmişse bu çalışmaz. onItemSelected çağrılacaktır.
Arash

62

API düzey 3'ten başlayarak, kullanıcının bir cihazla etkileşime girip girmediğini belirlemek için bir boole içeren bir Etkinlikte onUserInteraction () yöntemini kullanabilirsiniz.

http://developer.android.com/reference/android/app/Activity.html#onUserInteraction ()

@Override
public void onUserInteraction() {
     super.onUserInteraction();
     userIsInteracting = true;
}

Faaliyet alanım olarak:

 private boolean userIsInteracting;

Sonunda çeviricim:

      mSpinnerView.setOnItemSelectedListener(new OnItemSelectedListener() {

           @Override
           public void onItemSelected(AdapterView<?> arg0, View view, int position, long arg3) {
                spinnerAdapter.setmPreviousSelectedIndex(position);
                if (userIsInteracting) {
                     updateGUI();
                }
           }

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

           }
      });

Siz gelip etkinlik boyunca ilerlediğinizde boolean, false değerine sıfırlanır. Tıkır tıkır çalışıyor.


3
İyi bir Bill .. Bence bu cevap olarak kabul edilenlerden daha iyi bir çözüm
Ritesh Gune

setmPreviousSelectedIndex'i nereden alıyorsunuz?!?!
TheQ

Tipo? :) setPreviousSelectedIndex ()
Bill Mote

4
Bu, yuva parçaları durumunda onUserInteraction Activity yöntemi olduğu için çalışmaz. Başka bir çözüm var mı?
Chitrang

1
@ErikB nvm, anladım. Dinleyicinin içinde yanlış ayarlanması iyi sonuç verir.
Sikander

20

Bu benim için çalıştı

Spinner'ın Android'de başlatılması sorunludur, bazen yukarıdaki sorun bu model ile çözülmüştür.

Spinner.setAdapter();
Spinner.setSelected(false);  // must
Spinner.setSelection(0,true);  //must
Spinner.setonItemSelectedListener(this);

Ayar adaptörü ilk kısım olmalıdır ve bir iplikçi başlatılırken onItemSelectedListener (bu) son olacaktır. Yukarıdaki desenle, değer değiştiricinin başlatılması sırasında OnItemSelected () yöntemim çağrılmaz


11

haha ... Aynı sorum var. İnitViews () sadece bunu yaptığınızda.Sira anahtardır, dinleyici sonuncusudur. İyi şanslar !

spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);

İyi bir! Hiçbir şey Daha önce ne yaptıysam benim için çalıştı ama bu benim için bir cazibe gibi çalıştı. Teşekkürler @TreeSouth
Deepika Lalra

11
Benim için aynı şekilde kullanılan spinner.setSelection (position, false) çalıştı. SetSelection (position) yöntemiyle dinleyici başlatma sırasında çağrıldı.
Mario Kutlev

2
@HugoGresse spinner.setSelection (0, false) işlevini çağırmayı deneyin; . Şey, şimdi zaten seçilmiş olduğundan, bu pozisyonun seçim göz ardı edecek
android geliştirici

8

Çözümüm:

protected boolean inhibit_spinner = true;


@Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int pos, long arg3) {

            if (inhibit_spinner) {
                inhibit_spinner = false;
            }else {

            if (getDataTask != null) getDataTask.cancel(true);
            updateData();
            }

        }

7

Başlatma sırasında spinner.setOnItemSelectedListener () yönteminin çağrılmasını önlemek için

spinner.setSelection(Adapter.NO_SELECTION, true); //Add this line before setting listener
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    }

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

    }
});

6

Bunu şu şekilde yapabilirsiniz:

AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            //set the text of TextView
        }

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

        }
    });

yourSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            yourSpinner.setOnItemSelectedListener(listener);
        }

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

        }
    });

İlk başta bir dinleyici oluşturuyorum ve değişken bir geri çağrı ile ilişkilendiriliyor; sonra anonim ikinci bir dinleyici oluşturmak ve bu ilk kez çağrıldığında, bu değişiklik dinleyici =]


3

Kullanıcı etkileşimi bayrağı onTouch yönteminde true olarak ayarlanabilir ve onItemSelected() ve seçim değişikliği sonra . Bu çözümü tercih ediyorum çünkü kullanıcı etkileşimi bayrağı, etkinlikteki istenen davranışı etkileyebilecek diğer görünümler için değil, yalnızca döndürücü için işleniyor.

Kodda:

Dönücü için dinleyicinizi oluşturun:

public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {

    boolean userSelect = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        userSelect = true;
        return false;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
        if (userSelect) { 
            userSelect = false;
            // Your selection handling code here
        }
    }

}

İkisi de bir şekilde spinner dinleyicisi ekleyin OnItemSelectedListenerve bir OnTouchListener:

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);

2

Birden çok döndürücüyü etkinleştiren benzer basit çözüm, AdapterView öğesini ilk kez onItemSelected (...) çalıştırıldığında Bağdaştırıcı'yı bir koleksiyona - Etkinlikler üst sınıfına - yerleştirmektir. Bu, üst sınıfta bir yöntem kümesini etkinleştirir ve birden çok AdapterView ve bunun için birden fazla iplikçiyi destekler.

Üst Sınıf ...

private Collection<AdapterView> AdapterViewCollection = new ArrayList<AdapterView>();

   protected boolean firstTimeThrough(AdapterView parent) {
    boolean firstTimeThrough = ! AdapterViewCollection.contains(parent);
    if (firstTimeThrough) {
       AdapterViewCollection.add(parent);
     }
    return firstTimeThrough;
   }

Alt sınıf ...

public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
      if (! firstTimeThrough(parent)) {
        String value = safeString(parent.getItemAtPosition(pos).toString());
        String extraMessage = EXTRA_MESSAGE;
        Intent sharedPreferencesDisplayIntent = new         Intent(SharedPreferencesSelectionActivity.this,SharedPreferencesDisplayActivity.class);
    sharedPreferencesDisplayIntent.putExtra(extraMessage,value);
    startActivity(sharedPreferencesDisplayIntent);
  }
  // don't execute the above code if its the first time through
  // do to onItemSelected being called during view initialization.

}


2

boolean alanı yarat

private boolean inispinner;

içinde aktivite yaratma

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (!inispinner) {
                inispinner = true;
                return;
            }
            //do your work here
        }

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

        }
    });

2

Bunu dene

spinner.postDelayed(new Runnable() {
        @Override
        public void run() {
            addListeners();
        }
    }, 1000);.o

1

Bunu önce setOnTouchListener sonra onOuch üzerine setOnItemSelectedListener ile başarabilirsiniz.

@Override
public boolean onTouch(final View view, final MotionEvent event) {
 view.setOnItemSelectedListener(this)
 return false;
}

Bunu seviyorum. Bir kullanıcı görünüme her dokunduğunda yeni bir dinleyici oluştursa da. Bu yüzden ilk oluşturulan dinleyiciyi önbelleğe almayı ve yeniden kullanmayı tercih ediyorum.
Vlad

1

Bu benim için çalıştı:

    spinner.setSelection(0, false);
    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spinner.setOnItemSelectedListener(listener);
            }, 500);

1

Abhi'nin cevabına dayanarak bu basit dinleyiciyi yaptım

class SpinnerListener constructor(private val onItemSelected: (position: Int) -> Unit) : AdapterView.OnItemSelectedListener {

    private var selectionCount = 0

    override fun onNothingSelected(parent: AdapterView<*>?) {
        //no op
    }

    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        if (selectionCount++ > 1) {
           onItemSelected(position)
        }
    }
}

0

Aynı sorun vardı ve bu benim için çalışıyor:

2 eğiricim var ve bunları başlatma sırasında ve diğer denetimlerle etkileşimler sırasında veya sunucudan veri aldıktan sonra güncelleştiriyorum.

İşte benim şablon:

public class MyClass extends <Activity/Fragment/Whatever> implements Spinner.OnItemSelectedListener {

    private void removeSpinnersListeners() {
        spn1.setOnItemSelectedListener(null);
        spn2.setOnItemSelectedListener(null);
    }

    private void setSpinnersListeners() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spn1.setOnItemSelectedListener(MyClass.this);
                spn2.setOnItemSelectedListener(MyClass.this);
            }
        }, 1);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // Your code here
    }

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

    }
}

Sınıf başlatılırken dinleyiciyi doğrudan ayarlamak yerine setSpinnersListeners () öğesini kullanın.

Runnable, değerlerini ayarladıktan hemen sonra döndürücünün onItemSelected öğesini tetiklemesini önler.

Değer değiştiriciyi güncellemeniz gerekiyorsa (bir sunucu çağrısı vb. Sonra) , güncelleme hatlarınızdan hemen önce removeSpinnersListeners () öğesini ve güncelleme hatlarından hemen sonra setSpinnersListeners () öğesini kullanın . Bu, güncellemeden sonra onItemSelected'ın tetiklenmesini önleyecektir.


0

kod

spinner.setOnTouchListener(new View.OnTouchListener() { 
@Override public boolean onTouch(View view, MotionEvent motionEvent) { isSpinnerTouch=true; return false; }});

holder.spinner_from.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int slot_position, long l) {
                if(isSpinnerTouch)
                {
                    Log.d("spinner_from", "spinner_from");
                    spinnerItemClickListener.onSpinnerItemClickListener(position, slot_position, AppConstant.FROM_SLOT_ONCLICK_CODE);
                }
                else {

                }
            }

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

            }
        });

0

Benim için Abhi'nin çözümü Api seviye 27'ye kadar harika çalışıyor.

Ancak Api düzey 28 ve sonrasında, dinleyici ayarlandığında onItemSelected () çağrılmaz, yani onItemSelected () hiçbir zaman çağrılmaz.

Bu nedenle, Api seviyesini kontrol etmek için kısa bir if ifadesi ekledim:

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {

            if(Build.VERSION.SDK_INT >= 28){ //onItemSelected() doesn't seem to be called when listener is set on Api 28+
                check = 1;
            }

            if(++check > 1) {
                //Do your action here
            }
        }

Bence bu oldukça garip ve başkalarının da bu problemi olup olmadığından emin değilim, ama benim durumumda iyi çalıştı.


0

Spinner'ın üstüne, Spinner ile aynı boyut ve arka plana bir TextView yerleştirdim, böylece kullanıcı üzerine tıklamadan önce neye benzediğini daha fazla kontrol edebilirdim. Orada TextView ile, kullanıcı etkileşime başladığında işaretlemek için TextView kullanabilirsiniz.

Kotlin kodum şuna benzer:

private var mySpinnerHasBeenTapped = false

private fun initializeMySpinner() {

    my_hint_text_view.setOnClickListener {
        mySpinnerHasBeenTapped = true //turn flag to true
        my_spinner.performClick() //call spinner click
    }

    //Basic spinner setup stuff
    val myList = listOf("Leonardo", "Michelangelo", "Rafael", "Donatello")
    val dataAdapter: ArrayAdapter<String> = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, myList)
    my_spinner.adapter = dataAdapter

    my_spinner.onItemSelectedListener = object : OnItemSelectedListener {

        override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {

            if (mySpinnerHasBeenTapped) { //code below will only run after the user has clicked
                my_hint_text_view.visibility = View.GONE //once an item has been selected, hide the textView
                //Perform action here
            }
        }

        override fun onNothingSelected(parent: AdapterView<*>?) {
            //Do nothing
        }
    }
}

Mizanpaj dosyası şuna benzer: Önemli kısım Spinner ve TextView'in aynı genişlik, yükseklik ve kenar boşluklarını paylaşmasıdır:

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Spinner
                android:id="@+id/my_spinner"
                android:layout_width="match_parent"
                android:layout_height="35dp"
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true" />

            <TextView
                android:id="@+id/my_hint_text_view"
                android:layout_width="match_parent"
                android:layout_height="35dp"                
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true"
                android:gravity="center_vertical"
                android:text="*Select A Turtle"
                android:textColor="@color/green_ooze"
                android:textSize="16sp" />

        </FrameLayout>

Eminim diğer çözümler ilk onItemSelected çağrısını göz ardı ettiğiniz yerde çalışır, ancak gerçekten her zaman çağrılacağını varsayma fikrini sevmiyorum.

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.