Android中使用Spinner有时有二级菜单需要操作,这时选中了某一项,想再点击这一项进入二级菜单重新选择时,onItemSelected方法是不会重新调用的,二级菜单出不来,影响功能。看Spinner源码,只有现在选中的position(或rowId)和点击的position(或rowId)不一样,才会触发onItemSelected回调。
AdapterView.java:
void checkSelectionChanged() {
if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
selectionChanged();
mOldSelectedPosition = mSelectedPosition;
mOldSelectedRowId = mSelectedRowId;
}
}
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();
}
}
}
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);
}
}
那么方案就是让点击的position(或mSelectedRowId )和之前的position(或mSelectedRowId )不一样即可让回调方法执行。那么拦截onTouch事件,在其中将mOldSelectedPosition或mOldSelectedRowId改为不会和现在点击的一样即可。方法如下:
spinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
try {
Class<?> clazz = AdapterView.class;
//Field field = clazz.getDeclaredField("mOldSelectedPosition");
//field.setAccessible(true);
//field.setInt(spn,-1);
Field field = clazz.getDeclaredField("mOldSelectedRowId");
field.setAccessible(true);
field.setInt(spn_ps,Integer.MIN_VALUE);
} catch(Exception e){
e.printStackTrace();
}
return false;
}
});
onTouch返回false,这样事件可以继续传递下去,OnItemSelectedListener得以响应。