不希望的onItemSelected调用
我有36个spinners,我已经初始化了一些值。我已经使用onItemSelectedListener。像往常一样,用户可以与这些spinners进行交互,触发onItemSeected函数。不希望的onItemSelected调用
一个问题是初始化过程中调用时,但我在这里找到解决方案,并避免使用全局变量“计数”,并检查是否计数> 36的内部onItemSelected执行代码之前。
我的问题是这样的: 用户可以选择点击一个叫做“Previous”的按钮,在这个按钮上我必须重置一些微调值。
我试着在重置spinners之前将count的值改为0,然后在重置后将它重新更改为37,但是我明白了onItemSelected仅在每个其他函数执行完毕后才会调用,所以它称为AFTER计数会重新变回37,即使微调器值在用户选择时立即设置。
我需要反复刷新一些spinners而不会触发onItemSelected函数。任何人都可以帮我找到解决方案吗?谢谢。
我发现一个简单的,我认为,优雅的解决方案。 使用标签。 我先创建一个名为“标签”,把下面的代码一个新的XML文件:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item name="pos" type="id" />
</resources>
每当我自己用的spin.setSelection(pos)
,我也做spin.setTag(R.id.pos, pos)
,所以我设置的当前位置作为标记。
然后,在onItemSelected,我执行代码仅if(spin.getTag(R.id.pos) != position)
,其中位置是通过函数提供的位置可变。 这样,我的代码只有在用户正在进行选择时才会执行。 由于用户已经做出选择,标签还没有更新,所以处理完成后,我将标签更新为spin.setTag(R.id.pos, position)
。
注意:要使用整个同一个适配器是很重要的,还是“位置”变量可能指向不同的元素。
编辑:作为kaciula指出的那样,如果你不使用多个标签,则可以使用简单的版本,那就是spin.setTag(pos)
和spin.getTag()
而不需要一个XML文件。
好的解决方案!工作正常。我之前尝试了很多东西。谢谢! – Rafael
没问题!很高兴它为你工作:)请一个问题和答案。它可能会帮助其他人:) –
如果您不需要将几个标签附加到微调器,您还可以使用setTag(pos)的简化版本。这样你就不需要为密钥创建xml文件。 –
当Spinner.setSelection(位置)时,它总是激活setOnItemSelectedListener()
为了避免烧了两次代码我使用此解决方案:
private Boolean mIsSpinnerFirstCall = true;
...
Spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//If a new value is selected (avoid activating on setSelection())
if(!mIsSpinnerFirstCall) {
// Your code goes gere
}
mIsSpinnerFirstCall = false;
}
public void onNothingSelected(AdapterView<?> arg0) {
}
});
tks - 保持简单! – Guihgo
我解决的办法,这是通过保存首先OnItemSelectedListener。然后将Spinner的OnItemSelectedListener设置为空值。通过代码在微调器中设置项目后,再次恢复OnItemSelectedListener。这对我有效。
见下面的代码:
// disable the onItemClickListener before changing the selection by code. Set it back again afterwards
AdapterView.OnItemSelectedListener onItemSelectedListener = historyPeriodSpinner.getOnItemSelectedListener();
historyPeriodSpinner.setOnItemSelectedListener(null);
historyPeriodSpinner.setSelection(0);
historyPeriodSpinner.setOnItemSelectedListener(onItemSelectedListener);
这是一个好主意,但在调用setSelection()之后设置(非空)侦听器仍然会导致侦听器被调用。 – stevehs17
这里是我解决这个问题。我扩展AppCompatSpinner
并添加方法pgmSetSelection(int pos)
,该方法允许编程选择设置而不触发选择回调。我已经使用RxJava对此进行了编码,以便通过Observable
传递选择事件。
package com.controlj.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import io.reactivex.Observable;
/**
* Created by clyde on 22/11/17.
*/
public class FilteredSpinner extends android.support.v7.widget.AppCompatSpinner {
private int lastSelection = INVALID_POSITION;
public void pgmSetSelection(int i) {
lastSelection = i;
setSelection(i);
}
/**
* Observe item selections within this spinner. Events will not be delivered if they were triggered
* by a call to setSelection(). Selection of nothing will return an event equal to INVALID_POSITION
*
* @return an Observable delivering selection events
*/
public Observable<Integer> observeSelections() {
return Observable.create(emitter -> {
setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if(i != lastSelection) {
lastSelection = i;
emitter.onNext(i);
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
onItemSelected(adapterView, null, INVALID_POSITION, 0);
}
});
});
}
public FilteredSpinner(Context context) {
super(context);
}
public FilteredSpinner(Context context, int mode) {
super(context, mode);
}
public FilteredSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
super(context, attrs, defStyleAttr, mode);
}
}
在Fragment
例如它的用法,所谓在onCreateView()
的一个例子:
mySpinner = view.findViewById(R.id.history);
mySpinner.observeSelections()
.subscribe(this::setSelection);
其中setSelection()
是看起来像这样的包围视图的方法,并且其都从用户调用选择事件通过Observable
以及其他地方编程,因此处理选择的逻辑对于两种选择方法都是通用的。
private void setSelection(int position) {
if(adapter.isEmpty())
position = INVALID_POSITION;
else if(position >= adapter.getCount())
position = adapter.getCount() - 1;
MyData result = null;
mySpinner.pgmSetSelection(position);
if(position != INVALID_POSITION) {
result = adapter.getItem(position);
}
display(result); // show the selected item somewhere
}
我不知道,如果这个解决方案是在这里所选择的一个为做到万无一失,但它很适合我,似乎更简单:
boolean executeOnItemSelected = false;
spinner.setSelection(pos)
然后在OnItemSelectedListener
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(executeOnItemSelected){
//Perform desired action
} else {
executeOnItemSelected = true;
}
}
检查此问题:http://stackoverflow.com/questions/2562248/android-how-to-keep-onitemselected-from-firing-off-on-a-newly-instantiated-spin并尝试遵循布拉德的建议使用'setSelection()'。 –
我已经尝试使用setSelection()和false。 onItemSelected内部的代码仍然执行。 –
@Darth Vedar您可以使用方法setEnabled(true/false)按照您的要求禁用和启用微调器; – poojagupta