programing

아이템을 유지하는 방법새로 인스턴스화된 스피너에 대한 발사에서 선택되었습니까?

jooyons 2023. 6. 4. 10:30
반응형

아이템을 유지하는 방법새로 인스턴스화된 스피너에 대한 발사에서 선택되었습니까?

저는 이 문제를 해결할 수 있는 몇 가지 덜 우아한 방법을 생각해봤지만, 제가 뭔가를 놓치고 있는 것이 틀림없다는 것을 압니다.

나의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.
    }
}
}

Runnables의 사용이 완전히 잘못되었습니다.

사용하다setSelection(position, false);이전의 초기 선택에서.setOnItemSelectedListener(listener)

이렇게 하면 애니메이션 없이 선택한 항목의 수신기를 호출하도록 선택 항목을 설정할 수 있습니다.그러나 수신기가 null이므로 아무것도 실행되지 않습니다.그러면 수신기가 할당됩니다.

따라서 다음과 같은 정확한 순서를 따르십시오.

Spinner s = (Spinner)Util.findViewById(view, R.id.sound, R.id.spinner);
s.setAdapter(adapter);
s.setSelection(position, false);
s.setOnItemSelectedListener(listener);

하여 Dan Dyer님의 Dan Dyer님, Dan Dyer님을 .OnSelectListener순식간에post(Runnable)방법:

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

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

이 경우에는 수신기가 변경된 항목에 대해서만 실행된다는 의미이기도 합니다.

귀하의 솔루션이 작동할 것으로 예상했습니다. 수신기를 설정하기 전에 어댑터를 설정하면 선택 이벤트가 실행되지 않을 것이라고 생각했습니다.

즉, 단순 부울 플래그를 사용하면 로그 첫 번째 선택 이벤트를 탐지하고 무시할 수 있습니다.

변경을 위한 작은 유틸리티 방법을 만들었습니다.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 스레드와 비동기식이기 때문에 연속적인 핸들러 게시물에서 수행해야 한다는 것입니다.

안타깝게도 이 문제에 대해 가장 일반적으로 제안되는 두 가지 해결책, 즉 콜백 발생 횟수를 세는 것과 나중에 콜백을 설정할 수 있는 실행 가능을 게시하는 것은 모두 액세스 가능성 옵션이 활성화된 경우 실패할 수 있습니다.다음은 이러한 문제를 해결하는 도우미 클래스입니다.추가 설명은 댓글 블록에 있습니다.

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

}

제가 이 말을 할 때 저를 믿으세요, 이것이 가장 신뢰할 수 있는 해결책입니다.해킹, 하지만 효과가 있어요!

OnTouchListener를 사용하여 setOnItemSelectedListener(활동 초기화 등의 일부)에 대한 자동 호출과 실제 사용자 상호 작용에 의해 트리거된 호출을 구별하는 힌트를 얻기 위해 여기에서 다른 몇 가지 제안을 시도한 후 다음 작업을 수행했으며 가장 적은 줄의 코드에서 잘 작동한다는 것을 발견했습니다.

다음과 같이 활동/조각에 대한 부울 필드를 설정합니다.

private Boolean spinnerTouched = false;

그런 다음 스피너 세트 OnItemSelectedListener를 설정하기 직전에 onTouchListener를 설정합니다.

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

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    ...
         if (spinnerTouched){
         //Do the stuff you only want triggered by real user interaction.
        }
        spinnerTouched = false;

저도 비슷한 상황에 처해 있었고, 저에게 맞는 간단한 해결책이 있습니다.

인 것 요.setSelection(int position)그리고.setSelected(int position, boolean animate)내부 구현이 다릅니다.

방법을 는 두번방법사용는경우하을째우경▁when▁the는하▁you사용.setSelected(int position, boolean animate)flag를 하면 발사하지 할 수 .onItemSelected듣는 사람

spinner.setSelection(Adapter.NO_SELECTION, false);

코드를 다음과 같이 선택하는 경우 이 문제가 발생합니다.

   mSpinner.setSelection(0);

위의 문장 대신에 사용

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

편집: 이 방법은 Mi Android 버전 Mi UI에서는 사용할 수 없습니다.

오랫동안 머리를 빼다가 이제는 나만의 스피너 클래스를 만들었습니다.여기에 청취자의 연결을 적절히 끊고 연결하는 방법을 추가했습니다.

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이기 때문에 Android 재고에 포함되어야 합니다.

레이아웃이 완료될 때까지 수신기 추가를 연기하는 경우 레이아웃 단계에서 원하지 않는 이벤트가 발생하지 않습니다.

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) {
                }

            });

        }
    });

아주 간단한 답변을 받았습니다. 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
}

저는 이것에 대한 훨씬 더 우아한 해결책을 찾았습니다.어레이 어댑터("어댑터"의 경우)가 호출된 횟수를 계산합니다.한 명의 스피너가 있고 다음과 같이 전화한다고 가정해 보겠습니다.

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 카운터를 선언한 다음 Item 내부에 선언합니다.Selected() 메서드는 "if" 조건을 지정하여 어댑터가 호출된 횟수를 확인합니다.귀하의 경우 한 번만 전화를 걸면 다음과 같습니다.

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

아무 것도 나에게 효과가 없었고, 내가 보기에 한 명 이상의 스피너가 있기 때문에 (그리고 부울 지도를 들고 있는 IMHO는 오버킬입니다) 나는 클릭 수를 세기 위해 태그를 사용합니다.

spinner.setTag(0);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            Integer selections = (Integer) parent.getTag();
            if (selections > 0) {
                // real selection
            }
            parent.setTag(++selections); // (or even just '1')
        }

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

저의 작은 기여는 위의 몇 가지 사항에 대한 변형으로 저에게 몇 번 적합했습니다.

정수 변수를 기본값(또는 기본 설정에 저장된 마지막으로 사용된 값)으로 선언합니다.스피너를 사용합니다.수신기가 등록되기 전에 해당 값을 설정하려면 setSelection(myDefault)을 선택합니다.onItem에서선택하면 추가 코드를 실행하기 전에 새 스피너 값이 사용자가 할당한 값과 동일한지 확인합니다.

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

저는 같은 문제를 겪은 후에 태그를 사용하여 이 솔루션에 도달했습니다.그 이면에 있는 아이디어는 간단합니다.스피너가 프로그램적으로 변경될 때마다 태그가 선택한 위치를 반영하는지 확인합니다.그런 다음 수신기에서 선택한 위치가 태그와 동일한지 확인합니다.만약 그렇다면, 스피너 선택이 프로그램적으로 변경되었습니다.

다음은 저의 새로운 "스피너 프록시" 클래스입니다.

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.
}

또태설포함된 XML 합필다에 합니다.Values디렉토리입니다.파일 이름을 지정했습니다.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.

이 래퍼는 레이아웃 작성 중에 수신기가 호출되는 문제도 처리합니다.

재미있게 놀아, 젠스.

이미 많은 답이 있습니다. 여기 제 답이 있습니다.

연장합니다AppCompatSpinner합니다.pgmSetSelection(int pos)선택 콜백을 트리거하지 않고 프로그래밍 방식의 선택 설정을 허용합니다.가 RxJava의 RxJava를 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<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);
    }
}

예용출예라고 불리는 onCreateView()순식간에Fragment예:

    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.setOnItemSelectedListener(new MyOnItemSelectedListener());

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

항상 하위 분류와 함께 사용할 수 있는 솔루션이 있습니다. 여기서 부울 플래그를 재정의된 setAdapter 메서드에 래핑하여 이벤트를 건너뛸 수 있습니다.

부울 플래그나 카운터가 있는 솔루션은 도움이 되지 않았습니다. 항목에서 방향 변경 중이었기 때문입니다.선택()은 플래그 또는 카운터를 "overflow" 호출합니다.

하위 분류했습니다.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;
}

이것 또한 우아한 해결책이 아닙니다.사실 그것은 오히려 루브 골드버그이지만 효과가 있는 것처럼 보입니다.어레이 어댑터를 확장하고 getDropDownView를 재정의하여 스피너를 한 번 이상 사용했는지 확인합니다.새로운 getDropDownView 메서드에서 드롭다운 메뉴가 한 번 이상 사용되었음을 표시하도록 설정된 부울 플래그가 있습니다.플래그가 설정될 때까지 수신기에 대한 호출을 무시합니다.

주 활동.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;
}

전단지에서 활동을 다시 만들어야 하는 경우: 테마를 변경하면 간단한 플래그/카운터가 작동하지 않습니다.

onUserInteraction() 함수를 사용하여 사용자 활동을 탐지합니다.

참조: https://stackoverflow.com/a/25070696/4772917

간단한 방법으로 완료했습니다.

private AdapterView.OnItemSelectedListener listener;
private Spinner spinner;

작성 시();

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) {

        }
    });

다 했어요.

if () {        
       spinner.setSelection(0);// No reaction to create spinner !!!
     } else {
        spinner.setSelection(intPosition);
     }


spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

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

         if (position > 0) {
           // real selection
         }

      }

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

     }
});

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

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 콜백을 트리거하지 않고 스피너의 항목을 선택합니다.

사용해야 합니다.mSpinner볼 수 있는홀더, 그래서 깃발.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
            }
        });

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

나의 솔루션은onTouchListener사용을 제한하지 않습니다.다음을 위한 포장지를 만듭니다.onTouchListener필요한 경우 설치onItemSelectedListener.

public class Spinner extends android.widget.Spinner {
    /* ...constructors... */

    private OnTouchListener onTouchListener;
    private OnItemSelectedListener onItemSelectedListener;

    @Override
    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        onItemSelectedListener = listener;
        super.setOnTouchListener(wrapTouchListener(onTouchListener, onItemSelectedListener));
    }

    @Override
    public void setOnTouchListener(OnTouchListener listener) {
        onTouchListener = listener;
        super.setOnTouchListener(wrapTouchListener(onTouchListener, onItemSelectedListener));
    }

    private OnTouchListener wrapTouchListener(final OnTouchListener onTouchListener, final OnItemSelectedListener onItemSelectedListener) {
        return onItemSelectedListener != null ? new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                Spinner.super.setOnItemSelectedListener(onItemSelectedListener);
                return onTouchListener != null && onTouchListener.onTouch(view, motionEvent);
            }
        } : onTouchListener;
    }
}

제가 게시물을 보고 답변이 너무 늦어질 수도 있지만 Android Data 바인딩 라이브러리 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 사용자 지정 설정기에서 확인할 수 있습니다.

메모

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

       android {
     ....
     dataBinding {
     enabled = true
    }
    }
    
  2. 을 레아파에 합니다.<layout>꼬리표

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

언급URL : https://stackoverflow.com/questions/2562248/how-to-keep-onitemselected-from-firing-off-on-a-newly-instantiated-spinner

반응형