Android Spinner:避免初始化过程中的onItemSelected调用

我用SpinnerTextView创建了一个Android应用程序。我想在TextView中显示从旋转器的下拉列表中选中的项目。我在onCreate方法中实现了Spinner,因此当我运行程序时,它会在TextView中显示一个值(在从下拉列表中选择一个项之前)。

我想显示在TextView的值后,才从下拉列表选择了一个项目。我怎么做呢?

这是我的代码:

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


}
}
114226 次浏览
spinner.setOnItemSelectedListener(this); // Will call onItemSelected() Listener.

所以第一次用任何Integer值来处理这个

< p >的例子: 初始取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);
}
}

你可以用布尔值来做,也可以检查当前和以前的位置。在这里看到的

类似的支持多个旋转器的简单解决方案是在第一次执行onItemSelected(…)时将AdapterView放在一个集合中-在Activities超类中然后在执行它之前检查AdapterView是否在集合中。这将在超类中启用一组方法,并支持多个adapterview,从而支持多个旋转器。

超类…

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


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

子类……

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.

我的解决方案:

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


}

你可以这样做:

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


}
});

首先我创建了一个监听器,并归属于一个变量回调;然后我创建了第二个匿名侦听器,当它第一次被调用时,这改变了侦听器 =] < / p >

从API级别3开始,你可以在一个带有布尔值的Activity上使用onUserInteraction()来确定用户是否正在与设备交互。

< a href = " http://developer.android.com/reference/android/app/Activity.html onUserInteraction () " > http://developer.android.com/reference/android/app/Activity.html onUserInteraction () < / >

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

作为一个字段的活动我有:

 private boolean userIsInteracting;

最后,我的旋转器:

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


}
});

当你通过活动时,布尔值被重置为false。效果非常好。

< p >哈哈…我也有同样的问题。 当initViews()这样做。顺序是关键,监听器是最后。

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

我也有同样的问题,这个方法对我很管用:

我有2个旋转器,我在初始化和与其他控件交互期间或从服务器获取数据后更新它们。

下面是我的模板:

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


}
}

当类初始化时,使用setSpinnersListeners ()而不是直接设置侦听器。

Runnable将防止旋转器在你设置它们的值后立即触发onItemSelected。

如果你需要更新微调器(在服务器调用之后等),在更新行之前使用removeSpinnersListeners (),在更新行之后使用setSpinnersListeners ()。这将防止onItemSelected在更新后被触发。

你可以通过先setOnTouchListener,然后在onTouch中setOnItemSelectedListener来实现

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

只需要将这一行之前设置为OnItemSelectedListener

spinner.setSelection(0,false)

这是因为setSelection(int, boolean)在内部调用setSelectionInt(),因此当添加侦听器时,该项已经被选中。

注意setSelection(int)不能工作,因为它在内部调用setNextSelectedPositionInt()

然后,用户交互标志可以在onTouch方法中设置为true,并在onItemSelected()中重新设置,一旦选择更改被处理。我更喜欢这个解决方案,因为用户交互标志是专门为旋转器处理的,而不是为活动中可能影响预期行为的其他视图处理的。

在代码:

为旋转器创建监听器:

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


}

将监听器同时作为OnItemSelectedListenerOnTouchListener添加到旋转器:

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

这对我很有效

Spinner在Android中的初始化有时是有问题的

.

.

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

设置适配器应该是第一部分,onItemSelectedListener(这个)将是初始化旋转器时的最后一部分。通过上面的模式,我的OnItemSelected()在初始化spinner期间没有被调用

避免在初始化过程中调用spinner.setOnItemSelectedListener()

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


}
});

创建一个布尔字段

private boolean inispinner;

在活动的oncreate内部

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


}
});

试试这个

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

这招对我很管用:

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

根据Abhi的回答,我做了这个简单的监听器

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

代码

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


}
});

对我来说,Abhi的解决方案在Api级别27之前非常有效。

但似乎从Api级别28及以上,onItemSelected()不被调用时,监听器被设置,这意味着onItemSelected()永远不会被调用。

因此,我添加了一个简短的if语句来检查Api级别:

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

我认为这很奇怪,我不确定其他人是否也有这个问题,但在我的情况下,它运行得很好。

我把一个TextView放在Spinner的顶部,与Spinner的大小和背景相同,这样我就可以在用户点击它之前对它的外观有更多的控制。有了TextView,我也可以使用TextView标记,当用户已经开始交互。

我的Kotlin代码是这样的:

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

布局文件看起来是这样的,重要的部分是,Spinner和TextView共享相同的宽度,高度和边距:

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

我确信其他的解决方案可以忽略第一个onItemSelected调用,但我真的不喜欢假设它总是被调用的想法。

你可以像这样创建自定义OnItemSelectedListener。我已经采取了val check=0onItemSelected()方法,我检查它的计数是否为0?如果0表示它在初始化时被调用。所以忽略它吧。

我还调用了一个单独的抽象方法onUserItemSelected(),我将这个方法称为check > 0。这对我来说非常好。

abstract class MySpinnerItemSelectionListener : AdapterView.OnItemSelectedListener {


abstract fun onUserItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long)
private var check = 0
override fun onItemSelected(
parent: AdapterView<*>?,
view: View,
position: Int,
id: Long
) {
if (++check > 1) {
onUserItemSelected(parent, view, position, id)
}
}


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

然后你可以像这样设置监听器。

mySpinner.onItemSelectedListener =  object : MySpinnerItemSelectionListener() {
override fun onUserItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
//your user selection spinner code goes here
}


}
我是这样解决这个问题的: 在名称为onResume()的活动生命周期方法中: 我添加了Spinner.setOnItemSelectedListener(this) 结果,当我们的旋转器在初始化中调用onclick方法时,它不起作用。

. onResume方法在Android完成页面显示时开始工作