Android Spinner不触发onItemSelected事件
程序员文章站
2022-07-04 18:50:14
...
Spinner不触发onItemSelected事件
最近有个项目,很久之前做的了,里边的选择方式用的都是Spinner,遇到了几个问题点
- 再次选择同一个选项时没有触发onItemSelected事件
- 如何自动弹出Spinner
- 初始化的时候就会走一遍回调事件
进入源码中找到setOnItemSelectedListener方法。
/**
* Register a callback to be invoked when an item in this AdapterView has
* been selected.
*
* @param listener The callback that will run
*/
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
mOnItemSelectedListener = listener;
}
然后mOnItemSelectedListener 这个监听对象在哪儿调用onItemSelected方法呢,也就触发了onItemSelected事件。
那么好,我们可以直接找到哪儿调用了。源码如下:
private void fireOnSelected() {
if (mOnItemSelectedListener == null) {
return;
}
final int selection = getSelectedItemPosition();
if (selection >= 0) {
View v = getSelectedView();
mOnItemSelectedListener.onItemSelected(this, v, selection,
getAdapter().getItemId(selection));
} else {
mOnItemSelectedListener.onNothingSelected(this);
}
}
那么什么地方调用了fireOnSelected()呢?最终我们找到了这个地方,源码如下:
void selectionChanged() {
if (mOnItemSelectedListener != null
|| AccessibilityManager.getInstance(mContext).isEnabled()) {
if (mInLayout || mBlockLayoutRequests) {
// If we are in a layout traversal, defer notification
// by posting. This ensures that the view tree is
// in a consistent state and is able to accomodate
// new layout or invalidate requests.
if (mSelectionNotifier == null) {
mSelectionNotifier = new SelectionNotifier();
}
post(mSelectionNotifier);
} else {
fireOnSelected();
performAccessibilityActionsOnSelected();
}
}
}
调用selectionChanged()方法是:
void checkSelectionChanged() {
if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
selectionChanged();
mOldSelectedPosition = mSelectedPosition;
mOldSelectedRowId = mSelectedRowId;
}
}
我们看这个判断 if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)),比较当前选项的位置与上一次选择的位置是否不相同,如果不相同就可以调用selectionChanged()执行onItemSelected事件。这就是选择一项时,必须与上一次选项的位置不相同才可以触发选择事件。否则不会执行。那么既然我们找这个条件,我们可以来修改上一次位置的值,只要与当前选择的位置不同就可以出发事件了。因为mOldSelectedPosition是私有属性,所以我们需要使用反射来修改mOldSelectedPosition的值。代码如下:
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
try {
Field field = AdapterView.class.getDeclaredField("mOldSelectedPosition");
field.setAccessible(true); //设置mOldSelectedPosition可访问
field.setInt(spinner, AdapterView.INVALID_POSITION); //设置mOldSelectedPosition的值
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
这也就 解释了第一个和第三个问题
那么第二个问题呢=就很是简单了,直接调用spinner.perFormClick()即可
推荐阅读