Undesired onItemSelected calls

后端 未结 5 1012
半阙折子戏
半阙折子戏 2020-12-02 19:04

I have 36 spinners that I have initialized with some values. I have used onItemSelectedListener with them. As usual, the user can interact with these spinners, firing the on

5条回答
  •  甜味超标
    2020-12-02 19:43

    Here's my solution to this problem. I extend AppCompatSpinner and add a method pgmSetSelection(int pos) that allows programmatic selection setting without triggering a selection callback. I've coded this with RxJava so that the selection events are delivered via an 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 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);
        }
    }
    

    An example of its usage, called in onCreateView() in a Fragment for example:

        mySpinner = view.findViewById(R.id.history);
        mySpinner.observeSelections()
            .subscribe(this::setSelection);
    

    where setSelection() is a method in the enclosing view that looks like this, and which is called both from user selection events via the Observable and also elsewhere programmatically, so the logic for handling selections is common to both selection methods.

    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
    }
    

提交回复
热议问题