android setselection 어떻게 새롭게 인스턴스화 된 Spinner에서 onItemSelected가 발사되는 것을 막기 위해?




setonitemselectedlistener setselection (24)

동일한 문제가 발생한 후에 태그를 사용하여이 솔루션에 도달했습니다. 배후의 아이디어는 간단합니다. 프로그래밍 방식으로 회 전자가 변경 될 때마다 태그가 선택한 위치를 반영하는지 확인하십시오. 리스너에서 선택한 위치가 태그와 같은지 확인합니다. 이 경우 스피너 선택이 프로그래밍 방식으로 변경되었습니다.

아래는 새로운 "회 전자 프록시"클래스입니다.

package com.samplepackage;

import com.samplepackage.R;
import android.widget.Spinner;

public class SpinnerFixed {

    private Spinner mSpinner;

    public SpinnerFixed(View spinner) {
         mSpinner = (Spinner)spinner;
         mSpinner.setTag(R.id.spinner_pos, -2);
    }

    public boolean isUiTriggered() {
         int tag = ((Integer)mSpinner.getTag(R.id.spinner_pos)).intValue();
         int pos = mSpinner.getSelectedItemPosition();
         mSpinner.setTag(R.id.spinner_pos, pos);
         return (tag != -2 && tag != pos);
    }

    public void setSelection(int position) {
        mSpinner.setTag(R.id.spinner_pos, position);
        mSpinner.setSelection(position);
    }

    public void setSelection(int position, boolean animate) {
        mSpinner.setTag(R.id.spinner_pos, position);
        mSpinner.setSelection(position, animate);
    }

    // If you need to proxy more methods, use "Generate Delegate Methods"
    // from the context menu in Eclipse.
}

Values 디렉토리에 태그 설정이 포함 된 XML 파일이 필요합니다. 내 파일 이름을 spinner_tag.xml 이라고했지만, 그건 당신에게 spinner_tag.xml 습니다. 다음과 같이 보입니다.

<resources xmlns:android="http://schemas.android.com/apk/res/android">
  <item name="spinner_pos" type="id" />
</resources>

지금 바꾸기

Spinner myspinner;
...
myspinner = (Spinner)findViewById(R.id.myspinner);

코드로

SpinnerFixed myspinner;
...
myspinner = new SpinnerFixed(findViewById(R.id.myspinner));

그리고 핸들러를 다음과 같이 보입니다.

myspinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (myspinner.isUiTriggered()) {
            // Code you want to execute only on UI selects of the spinner
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }
});

isUiTriggered() 함수는 회 전자가 사용자에 의해 변경된 경우에만 true를 반환합니다. 이 함수에는 부작용이 있습니다. 태그를 설정하므로 동일한 수신기 호출에서 두 번째 호출은 항상 false 반환합니다.

이 랩퍼는 레이아웃 작성 중 호출되는 리스너와 관련된 문제점도 처리합니다.

즐겁게, 옌스.

나는이 문제를 해결할 수있는 우아한 방법보다는 덜 생각해 왔지만 뭔가를 놓치고 있어야한다는 것을 안다.

onItemSelected 는 사용자와의 상호 작용없이 즉각적으로 실행되며 바람직하지 않은 동작입니다. UI가 무엇인가를하기 전에 사용자가 무언가를 선택할 때까지 기다려야한다.

나는 심지어 도움이되기를 희망하면서 onResume() 에서 리스너를 설정하려고 시도했지만, 그렇지 않다.

사용자가 컨트롤을 터치하기 전에 어떻게 해고하지 못하게 할 수 있습니까?

public class CMSHome extends Activity { 

private Spinner spinner;

@Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // Heres my spinner ///////////////////////////////////////////
    spinner = (Spinner) findViewById(R.id.spinner);
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.pm_list, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
    };

public void onResume() {
    super.onResume();
    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}

    public class MyOnItemSelectedListener implements OnItemSelectedListener {

    public void onItemSelected(AdapterView<?> parent,
        View view, int pos, long id) {

     Intent i = new Intent(CMSHome.this, ListProjects.class);
     i.putExtra("bEmpID", parent.getItemAtPosition(pos).toString());
        startActivity(i);

        Toast.makeText(parent.getContext(), "The pm is " +
          parent.getItemAtPosition(pos).toString(), Toast.LENGTH_LONG).show();
    }

    public void onNothingSelected(AdapterView parent) {
      // Do nothing.
    }
}
}

나는 전화하려고 노력할 것이다.

spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());

setAdapter ()를 호출 한 후. 또한 어댑터 전에 호출 해보십시오.

서브 클래 싱을 사용하는 솔루션은 항상 있습니다. 오버라이드 된 setAdapter 메소드에 부울 플래그를 래핑하여 이벤트를 건너 뛸 수 있습니다.


나는 비슷한 상황에 있었고, 나는 나를 위해 일하는 간단한 해결책을 가지고있다.

그것은 setSelection(int position)setSelected(int position, boolean animate) 가 다른 내부 구현을 가지고있는 것처럼 보입니다.

두 번째 메서드 인 setSelected(int position, boolean animate) 를 false animate 플래그와 함께 사용하면 onItemSelected 수신기를 시작하지 않고 선택 항목을 가져옵니다.


내가 한 간단한 방법으로 :

private AdapterView.OnItemSelectedListener listener;
private Spinner spinner;

onCreate ();

spinner = (Spinner) findViewById(R.id.spinner);

listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {

            Log.i("H - Spinner selected position", position);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    };

 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            spinner.setOnItemSelectedListener(listener);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

끝난


즉흥적으로 활동을 재 작성해야하는 경우 : 테마 변경, 단순 플래그 / 카운터 작동 실패

onUserInteraction () 함수를 사용하여 사용자 활동을 감지하고,

reference : https://.com/a/25070696/4772917


내가 사용할 필요가 mSpinnerViewHolder에, 그래서 플래그는 mOldPosition익명 내부 클래스에 설정됩니다.

mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            int mOldPosition = mSpinner.getSelectedItemPosition();

            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long l) {
                if (mOldPosition != position) {
                    mOldPosition = position;
                    //Do something
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
                //Do something
            }
        });

이것은 코드에서 선택을하는 경우에 발생합니다.

   mSpinner.setSelection(0);

위의 진술 대신

   mSpinner.setSelection(0,false);//just simply do not animate it.

편집 :이 방법은 Mi 안드로이드 버전 Mi UI 작동하지 않습니다.


나는 이것에 훨씬 더 우아한 해결책을 발견했다. 그것은 ArrayAdapter (귀하의 경우 "어댑터")가 호출 된 횟수를 세는 것입니다. 1 개의 회 전자를 가지고 있다고 가정 해 보겠습니다.

int iCountAdapterCalls = 0;

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.pm_list, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

onCreate 뒤에 int 카운터를 선언 한 다음 onItemSelected () 메서드 내부에 "if"조건을 넣어 atapter가 호출 된 횟수를 확인합니다. 당신의 경우에는 한 번만 불렀습니다.

if(iCountAdapterCalls < 1)
{
  iCountAdapterCalls++;
  //This section executes in onCreate, during the initialization
}
else
{
  //This section corresponds to user clicks, after the initialization
}

그것이 나의 최종적이고 사용하기 쉬운 솔루션입니다.

public class ManualSelectedSpinner extends Spinner {
    //get a reference for the internal listener
    private OnItemSelectedListener mListener;

    public ManualSelectedSpinner(Context context) {
        super(context);
    }

    public ManualSelectedSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ManualSelectedSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) {
        mListener = listener;
        super.setOnItemSelectedListener(listener);
    }

    public void setSelectionWithoutInformListener(int position){
        super.setOnItemSelectedListener(null);
        super.setSelection(position);
        super.setOnItemSelectedListener(mListener);
    }

    public void setSelectionWithoutInformListener(int position, boolean animate){
        super.setOnItemSelectedListener(null);
        super.setSelection(position, animate);
        super.setOnItemSelectedListener(mListener);
    }
}

setSelection(...)기본 동작에 기본값 을 사용 하거나 setSelectionWithoutInformListener(...)OnItemSelectedListener 콜백을 트리거하지 않고 회 전자에서 항목을 선택하는 데 사용 합니다.


나는 사용자에게 알리지 않고 Spinner 선택을 바꾸기위한 작은 유틸리티 메소드를 만들었다 :

private void setSpinnerSelectionWithoutCallingListener(final Spinner spinner, final int selection) {
    final OnItemSelectedListener l = spinner.getOnItemSelectedListener();
    spinner.setOnItemSelectedListener(null);
    spinner.post(new Runnable() {
        @Override
        public void run() {
            spinner.setSelection(selection);
            spinner.post(new Runnable() {
                @Override
                public void run() {
                    spinner.setOnItemSelectedListener(l);
                }
            });
        }
    });
}

리스너를 비활성화하고 선택을 변경 한 다음 리스너를 다시 활성화합니다.

트릭은 호출이 UI 스레드와 비동기 적이므로 연속적인 핸들러 게시물에서 호출을 수행해야한다는 것입니다.


레이아웃이 끝날 때까지 리스너 추가를 연기하면 레이아웃 단계에서 원하지 않는 이벤트가 발생하지 않습니다.

spinner.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Ensure you call it only once works for JELLY_BEAN and later
            spinner.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            // add the listener
            spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                    // check if pos has changed
                    // then do your work
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {
                }

            });

        }
    });

onClickListener 객체를 만드는 동안 초기 인덱스를 저장합니다.

   int thisInitialIndex = 0;//change as needed

   myspinner.setSelection(thisInitialIndex);

   myspinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

      int initIndex = thisInitialIndex;

      @Override
      public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
         if (id != initIndex) { //if selectedIndex is the same as initial value
            // your real onselecteditemchange event
         }
      }

      @Override
      public void onNothingSelected(AdapterView<?> parent) {
      }
  });

spinner.setSelection(Adapter.NO_SELECTION, false);

Dan Dyer의 답변을 참고하여 OnSelectListenerpost(Runnable) 메소드에 등록하십시오.

spinner.post(new Runnable() {
    public void run() {
        spinner.setOnItemSelectedListener(listener);
    }
});

나를 위해 그렇게함으로써 희망찬 행동이 마침내 일어났습니다.

이 경우 청취자가 변경된 항목에서만 실행된다는 것을 의미합니다.


이미 많은 답변이 있습니다.

AppCompatSpinner 확장하고 선택 콜백을 트리거하지 않고 프로그래밍 방식의 선택 설정을 허용하는 pgmSetSelection(int pos) 메서드를 추가합니다. Observable 통해 선택 이벤트가 전달되도록이 코드를 RxJava로 코딩했습니다.

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<Integer> 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);
    }
}

예를 들어 Fragment 에서 onCreateView() 에서 사용 된 사용 예 :

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

여기서 setSelection() 은 이와 같이 보이는 둘러보기의 메서드이며 Observable 통해 사용자 선택 이벤트에서 또는 프로그래밍 방식으로 다른 곳에서 호출되므로 선택을 처리하는 논리는 두 가지 선택 방법 모두에 공통입니다.

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
}

오랫동안 머리카락을 꺼내고 나면 Spinner 클래스를 만들었습니다. 리스너를 적절히 연결 해제하고 연결하는 메소드를 추가했습니다.

public class SaneSpinner extends Spinner {
    public SaneSpinner(Context context) {
        super(context);
    }

    public SaneSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SaneSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    // set the ceaseFireOnItemClickEvent argument to true to avoid firing an event
    public void setSelection(int position, boolean animate, boolean ceaseFireOnItemClickEvent) {
        OnItemSelectedListener l = getOnItemSelectedListener();
        if (ceaseFireOnItemClickEvent) {
            setOnItemSelectedListener(null);
        }

        super.setSelection(position, animate);

        if (ceaseFireOnItemClickEvent) {
            setOnItemSelectedListener(l);
        }
    }
}

XML에서 다음과 같이 사용하십시오.

<my.package.name.SaneSpinner
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/mySaneSpinner"
    android:entries="@array/supportedCurrenciesFullName"
    android:layout_weight="2" />

인플레이션 후에 SaneSpinner 인스턴스를 검색하고 다음과 같이 콜렉션 세트를 호출하면됩니다.

mMySaneSpinner.setSelection(1, true, true);

이를 통해 이벤트가 시작되지 않으며 사용자 상호 작용이 중단되지 않습니다. 이로 인해 코드가 복잡해졌습니다. 이것은 진짜로 PITA이기 때문에 주식 안드로이드에 포함되어야합니다.


내 작은 기여는 몇 번 나에게 적합했던 일부 위의 변형이다.

정수 변수를 기본값 (또는 환경 설정에 마지막으로 사용 된 값)으로 선언하십시오. 리스너가 등록되기 전에 spinner.setSelection (myDefault)을 사용하여 해당 값을 설정하십시오. onItemSelected에서 새로운 스피너 값이 추가 코드를 실행하기 전에 할당 한 값과 같은지 확인합니다.

사용자가 동일한 값을 다시 선택하면 코드를 실행하지 않는 이점이 있습니다.


불행히도이 문제에 대한 가장 일반적으로 제안되는 두 가지 해결책, 즉 콜백 발생 횟수 계산과 콜백 설정을위한 Runnable 게시는 나중에 접근성 옵션을 사용할 때 실패 할 수 있습니다. 다음은 이러한 문제를 해결하는 도우미 클래스입니다. 추가 설명은 주석 블록에 있습니다.

import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;

/**
 * Spinner Helper class that works around some common issues 
 * with the stock Android Spinner
 * 
 * A Spinner will normally call it's OnItemSelectedListener
 * when you use setSelection(...) in your initialization code. 
 * This is usually unwanted behavior, and a common work-around 
 * is to use spinner.post(...) with a Runnable to assign the 
 * OnItemSelectedListener after layout.
 * 
 * If you do not call setSelection(...) manually, the callback
 * may be called with the first item in the adapter you have 
 * set. The common work-around for that is to count callbacks.
 * 
 * While these workarounds usually *seem* to work, the callback
 * may still be called repeatedly for other reasons while the 
 * selection hasn't actually changed. This will happen for 
 * example, if the user has accessibility options enabled - 
 * which is more common than you might think as several apps 
 * use this for different purposes, like detecting which 
 * notifications are active.
 * 
 * Ideally, your OnItemSelectedListener callback should be
 * coded defensively so that no problem would occur even
 * if the callback was called repeatedly with the same values
 * without any user interaction, so no workarounds are needed.
 * 
 * This class does that for you. It keeps track of the values
 * you have set with the setSelection(...) methods, and 
 * proxies the OnItemSelectedListener callback so your callback
 * only gets called if the selected item's position differs 
 * from the one you have set by code, or the first item if you
 * did not set it.
 * 
 * This also means that if the user actually clicks the item
 * that was previously selected by code (or the first item
 * if you didn't set a selection by code), the callback will 
 * not fire.
 * 
 * To implement, replace current occurrences of:
 * 
 *     Spinner spinner = 
 *         (Spinner)findViewById(R.id.xxx);
 *     
 * with:
 * 
 *     SpinnerHelper spinner = 
 *         new SpinnerHelper(findViewById(R.id.xxx))
 *         
 * SpinnerHelper proxies the (my) most used calls to Spinner
 * but not all of them. Should a method not be available, use: 
 * 
 *      spinner.getSpinner().someMethod(...)
 *
 * Or just add the proxy method yourself :)
 * 
 * (Quickly) Tested on devices from 2.3.6 through 4.2.2
 * 
 * @author Jorrit "Chainfire" Jongma
 * @license WTFPL (do whatever you want with this, nobody cares)
 */
public class SpinnerHelper implements OnItemSelectedListener {
    private final Spinner spinner;

    private int lastPosition = -1;
    private OnItemSelectedListener proxiedItemSelectedListener = null;  

    public SpinnerHelper(Object spinner) {
         this.spinner = (spinner != null) ? (Spinner)spinner : null;        
    }

    public Spinner getSpinner() {
        return spinner;
    }

    public void setSelection(int position) { 
        lastPosition = Math.max(-1, position);
        spinner.setSelection(position);     
    }

    public void setSelection(int position, boolean animate) {
        lastPosition = Math.max(-1, position);
        spinner.setSelection(position, animate);        
    }

    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        proxiedItemSelectedListener = listener;
        spinner.setOnItemSelectedListener(listener == null ? null : this);
    }   

    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (position != lastPosition) {
            lastPosition = position;
            if (proxiedItemSelectedListener != null) {
                proxiedItemSelectedListener.onItemSelected(
                        parent, view, position, id
                );
            }
        }
    }

    public void onNothingSelected(AdapterView<?> parent) {
        if (-1 != lastPosition) {
            lastPosition = -1;
            if (proxiedItemSelectedListener != null) {
                proxiedItemSelectedListener.onNothingSelected(
                        parent
                );
            }
        }
    }

    public void setAdapter(SpinnerAdapter adapter) {
        if (adapter.getCount() > 0) {
            lastPosition = 0;
        }
        spinner.setAdapter(adapter);
    }

    public SpinnerAdapter getAdapter() { return spinner.getAdapter(); } 
    public int getCount() { return spinner.getCount(); }    
    public Object getItemAtPosition(int position) { return spinner.getItemAtPosition(position); }   
    public long getItemIdAtPosition(int position) { return spinner.getItemIdAtPosition(position); }
    public Object getSelectedItem() { return spinner.getSelectedItem(); }
    public long getSelectedItemId() { return spinner.getSelectedItemId(); }
    public int getSelectedItemPosition() { return spinner.getSelectedItemPosition(); }
    public void setEnabled(boolean enabled) { spinner.setEnabled(enabled); }
    public boolean isEnabled() { return spinner.isEnabled(); }
}

내가 원하지 않았던 스피너의 발사와 관련하여 많은 문제를 겪었으며 모든 대답은 신뢰할 수 없습니다. 그들은 작동하지만 가끔은. 결국에는 실패 할 시나리오에 빠지게되고 코드에 버그가 생깁니다.

필자가 선택한 마지막 인덱스를 변수에 저장하고이를 리스너에서 평가하는 것이 효과적이었습니다. 새로운 선택 인덱스와 동일한 경우 아무 것도하지 않고 반환하고, 그렇지 않으면 리스너를 계속 진행합니다. 이 작업을 수행:

//Declare a int member variable and initialize to 0 (at the top of your class)
private int mLastSpinnerPosition = 0;

//then evaluate it in your listener
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {

  if(mLastSpinnerPosition == i){
        return; //do nothing
  }

  mLastSpinnerPosition = i;
  //do the rest of your code now

}

내가 이것을 말할 때 나를 믿어 라, 이것이 가장 신뢰할만한 해결책이다. 해킹,하지만 작동합니다!


불리언 플래그 또는 카운터가있는 솔루션이 도움이되지 않았습니다. 왜냐하면 오리엔테이션 변경 중에 onItemSelected ()가 플래그 또는 카운터를 "오버플로"합니다.

나는 android.widget.Spinner 하위 클래스로 만들었고 작은 추가 항목을 만들었습니다. 관련 부분은 다음과 같습니다. 이 솔루션은 나를 위해 일했습니다.

private void setHandleOnItemSelected()
{
  final StackTraceElement [] elements = Thread.currentThread().getStackTrace();

  for (int index = 1; index < elements.length; index++)
  {
     handleOnItemSelected = elements[index].toString().indexOf("PerformClick") != -1; //$NON-NLS-1$

     if (handleOnItemSelected)
     {
        break;
     }
  }
}

@Override
public void setSelection(int position, boolean animate)
{
  super.setSelection(position, animate);

  setHandleOnItemSelected();
}

@Override
public void setSelection(int position)
{
  super.setSelection(position);

  setHandleOnItemSelected();
}

public boolean shouldHandleOnItemSelected()
{
  return handleOnItemSelected;
}

mYear.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View arg1, int item, long arg3) {
                if (mYearSpinnerAdapter.isEnabled(item)) {

                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });

나는 아주 간단한 답을 얻었고 100 % 확신 할 수있다.

boolean Touched=false; // this a a global variable

public void changetouchvalue()
{
   Touched=true;
}

// this code is written just before onItemSelectedListener

 spinner.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            System.out.println("Real touch felt.");
            changetouchvalue();
            return false;
        }
    });

//inside your spinner.SetonItemSelectedListener , you have a function named OnItemSelected iside that function write the following code

if(Touched)
{
 // the code u want to do in touch event
}

나는 포스트에 너무 늦게 대답하고 있을지 모르지만 안드로이드 데이터 바인딩 라이브러리 인 Android Databinding을 사용하여 이것을 달성 할 수있었습니다 . 선택한 항목이 변경 될 때까지 리스너가 호출되지 않도록 사용자 정의 바인딩을 만들었습니다. 사용자가 동일한 위치를 반복해서 선택하더라도 이벤트가 다시 발생하지 않습니다.

레이아웃 XML 파일

    <layout>
  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
xmlns:app="http://schemas.android.com/apk/res-auto">


<Spinner
    android:id="@+id/spinner"
    android:layout_width="150dp"
    android:layout_height="wrap_content"
    android:spinnerMode="dropdown"
    android:layout_below="@id/member_img"
    android:layout_marginTop="@dimen/activity_vertical_margin"
    android:background="@drawable/member_btn"
    android:padding="@dimen/activity_horizontal_margin"
    android:layout_marginStart="@dimen/activity_horizontal_margin"
    android:textColor="@color/colorAccent"
    app:position="@{0}"
    />
 </RelativeLayout>
 </layout>

app:position 선택한 위치를 통과하는 곳입니다.

사용자 정의 바인딩

  @BindingAdapter(value={ "position"}, requireAll=false)
  public static void setSpinnerAdapter(Spinner spinner, int selected) 
  {

    final int [] selectedposition= new int[1];
    selectedposition[0]=selected;


    // custom adapter or you can set default adapter
        CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(spinner.getContext(), <arraylist you want to add to spinner>);
        spinner.setAdapter(customSpinnerAdapter);
            spinner.setSelection(selected,false);


    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            String item = parent.getItemAtPosition(position).toString();
        if( position!=selectedposition[0]) {
                        selectedposition[0]=position;
            // do your stuff here
                    }
                }


        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    });
}

사용자 정의 데이터 바인딩에 대한 자세한 내용은 여기를 참조하십시오. Android Custom Setter

노트

  1. Gradle 파일에서 데이터 바인딩을 사용 설정하는 것을 잊지 마십시오.

       android {
     ....
     dataBinding {
     enabled = true
    }
    }
    
  2. <layout>태그에 레이아웃 파일 포함


이것은 우아한 해결책도 아닙니다. 사실 그것은 Rube-Goldberg 라기보다는 작동하는 것처럼 보입니다. 배열 어댑터를 확장하고 getDropDownView를 재정 의하여 회 전자가 적어도 한 번 이상 사용되었는지 확인합니다. 새 getDropDownView 메서드에는 적어도 한 번 이상 사용 된 드롭 다운 메뉴를 표시하도록 설정된 부울 플래그가 있습니다. 플래그가 설정 될 때까지 리스너에 대한 호출을 무시합니다.

MainActivity.onCreate () :

ActionBar ab = getActionBar();
ab.setDisplayShowTitleEnabled(false);
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
ab.setListNavigationCallbacks(null, null);

ArrayList<String> abList = new ArrayList<String>();
abList.add("line 1");
...

ArAd  abAdapt = new ArAd (this
   , android.R.layout.simple_list_item_1
   , android.R.id.text1, abList);
ab.setListNavigationCallbacks(abAdapt, MainActivity.this);

오버라이드 된 배열 어댑터 :

private static boolean viewed = false;
private class ArAd extends ArrayAdapter<String> {
    private ArAd(Activity a
            , int layoutId, int resId, ArrayList<String> list) {
        super(a, layoutId, resId, list);
        viewed = false;
    }
    @Override
    public View getDropDownView(int position, View convertView,
            ViewGroup parent) {
        viewed = true;
        return super.getDropDownView(position, convertView, parent);
    }
}

수정 된 리스너 :

@Override
public boolean onNavigationItemSelected(
   int itemPosition, long itemId) {
   if (viewed) {
     ...
   }
   return false;
}




android-spinner