Android Spinner不触发onItemSelected事件

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()即可

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值