美文网首页
Spinner选择同一项无法没有回调的解决方法

Spinner选择同一项无法没有回调的解决方法

作者: FreedApe | 来源:发表于2018-12-20 13:47 被阅读0次

    对于Spinner,也是最近项目需求用的,才去了解这个控件。项目里面的出生年月日,一开始使用OS标准的DatePicker,但是后来客户想要这样的。

    Spinner.png

    立马就想到了Spinner,于是就开始着手,具体的代码就不贴了。
    想要解决的是选择同一项的时候,也能回调
    void onItemSelected(AdapterView<?> parent, View view, int position, long id)方法。先看下为什么不能回调?

    AdapterView.class源码

    /**
         * 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(@Nullable 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()方法
    
     private void dispatchOnItemSelected() {
            fireOnSelected();
            performAccessibilityActionsOnSelected();
     }
    
     void selectionChanged() {
            // We're about to post or run the selection notifier, so we don't need
            // a pending notifier.
            mPendingSelectionNotifier = null;
    
            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 accommodate
                    // new layout or invalidate requests.
                    if (mSelectionNotifier == null) {
                        mSelectionNotifier = new SelectionNotifier();
                    } else {
                        removeCallbacks(mSelectionNotifier);
                    }
                    post(mSelectionNotifier);
                } else {
                    dispatchOnItemSelected();
                }
            }
            // Always notify AutoFillManager - it will return right away if autofill is disabled.
            final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
            if (afm != null) {
                afm.notifyValueChanged(this);
            }
        }
    
       /**
         * Called after layout to determine whether the selection position needs to
         * be updated. Also used to fire any pending selection events.
         */
        void checkSelectionChanged() {
            if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
                selectionChanged();
                mOldSelectedPosition = mSelectedPosition;
                mOldSelectedRowId = mSelectedRowId;
            }
    
            // If we have a pending selection notification -- and we won't if we
            // just fired one in selectionChanged() -- run it now.
            if (mPendingSelectionNotifier != null) {
                mPendingSelectionNotifier.run();
            }
        }
    

    我们看这个判断条件if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)),比较当前选项的位置与上一次选择的位置是否不相同,如果不相同就可以调用selectionChanged()执行onItemSelected事件。这就是选择一项时,必须与上一次选项的位置不相同才可以触发选择事件。

    那该如何解决?

    方法1:

    利用反射的方式修改上一次位置的值,只要与当前选择的位置不同就可以出发事件了。因为mOldSelectedPosition是私有属性,所以我们需要使用反射来修改mOldSelectedPosition的值。代码如下:

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        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<?> parent) {
    
    }
    
    

    如果页面只有一个Spinner是没有问题的,但是当页面包含了两个及以上的Spinner的时候就会出现一个问题:当点击第一个spinner的item时候,会触发其他Spinner的listener的onItemSelected方法,这就比较难受了,明明是只操作一个,但是其他也有响应。

    方法2

    在原有Spinner基础上自定义,代码不多

    public class CKDateSpinner extends AppCompatSpinner {
        public CKDateSpinner(Context context) {
            super(context);
        }
    
        public CKDateSpinner(Context context, int mode) {
            super(context, mode);
        }
    
        public CKDateSpinner(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public void setSelection(int position, boolean animate) {
            boolean sameSelected = position == getSelectedItemPosition();
            super.setSelection(position, animate);
            if (sameSelected) {
                // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
                getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
            }
        }
    
        @Override
        public void setSelection(int position) {
            boolean sameSelected = position == getSelectedItemPosition();
            super.setSelection(position);
            if (sameSelected) {
                // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
                getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
            }
        }
    }
    

    以上就是两种解决方法。

    相关文章

      网友评论

          本文标题:Spinner选择同一项无法没有回调的解决方法

          本文链接:https://www.haomeiwen.com/subject/molykqtx.html