현재 선택한 항목을 다시 선택할 때 Android Spinner에서 이벤트를 받으려면 어떻게해야합니까?
스피너 항목이 변경 될 때 응답 할 스피너에 대한 setOnItemSelectedListener를 작성했습니다. 내 요구 사항은 현재 선택한 항목을 다시 클릭하면 토스트가 표시되어야한다는 것입니다. 이 이벤트를받는 방법? 현재 선택한 항목을 다시 클릭하면 스피너가 응답하지 않습니다. `
StorageSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView adapter, View v, int i, long lng) {
Toast.makeText(getApplicationContext(), (CharSequence) StorageSpinner.getSelectedItem(), Toast.LENGTH_SHORT).show();
}
@Override
public void onNothingSelected(AdapterView arg0) {
Toast.makeText(getApplicationContext(), "Nothing selected", Toast.LENGTH_SHORT).show();
}
});
현재 선택된 항목을 다시 클릭하면 이벤트가 발생하지 않습니다. 따라서 스피너가 응답하도록 setOnItemSelectedListener를 잡을 수 없습니다.
이 문제를 해결하기 위해 몇 시간을 보냈습니다. 나는 다음과 같이 끝났다. 모든 경우에 작동하는지 확실하지 않지만 나를 위해 작동하는 것 같습니다. 선택을 확인하고 선택이 동일한 값으로 설정된 경우 리스너를 호출하는 Spinner 클래스의 확장 일뿐입니다.
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
/** Spinner extension that calls onItemSelected even when the selection is the same as its previous value */
public class NDSpinner extends Spinner {
public NDSpinner(Context context)
{ super(context); }
public NDSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public NDSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
@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());
}
}
}
이 시도
public class MySpinner extends Spinner{
OnItemSelectedListener listener;
public MySpinner(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
public void setSelection(int position)
{
super.setSelection(position);
if (position == getSelectedItemPosition())
{
listener.onItemSelected(null, null, position, 0);
}
}
public void setOnItemSelectedListener(OnItemSelectedListener listener)
{
this.listener = listener;
}
}
이 스피너는 항상 선택이 변경되었음을 알려줍니다.
package com.mitosoft.ui.widgets;
import java.lang.reflect.Method;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.AdapterView;
import android.widget.Spinner;
//com.mitosoft.ui.widgets.NoDefaultSpinner
public class NoDefaultSpinner extends Spinner {
private int lastSelected = 0;
private static Method s_pSelectionChangedMethod = null;
static {
try {
Class noparams[] = {};
Class targetClass = AdapterView.class;
s_pSelectionChangedMethod = targetClass.getDeclaredMethod("selectionChanged", noparams);
if (s_pSelectionChangedMethod != null) {
s_pSelectionChangedMethod.setAccessible(true);
}
} catch( Exception e ) {
Log.e("Custom spinner, reflection bug:", e.getMessage());
throw new RuntimeException(e);
}
}
public NoDefaultSpinner(Context context) {
super(context);
}
public NoDefaultSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void testReflectionForSelectionChanged() {
try {
Class noparams[] = {};
s_pSelectionChangedMethod.invoke(this, noparams);
} catch (Exception e) {
Log.e("Custom spinner, reflection bug: ", e.getMessage());
e.printStackTrace();
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
super.onClick(dialog, which);
if(lastSelected == which)
testReflectionForSelectionChanged();
lastSelected = which;
}
}
최신 Android 버전에서 작업하는 사람들을 위해 업데이트 된 답변을 남길 것이라고 생각했습니다.
적어도 4.1.2 및 4.3 (내가 테스트 한 장치)에서 작동하는 위 답변의 함수를 함께 컴파일했습니다. 이 함수는 리플렉션을 사용하지 않고 대신 마지막으로 선택한 인덱스 자체를 추적하므로 SDK가 클래스가 서로 확장되는 방식을 변경하더라도 안전하게 사용할 수 있습니다.
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
public class SelectAgainSpinner extends Spinner {
private int lastSelected = 0;
public SelectAgainSpinner(Context context)
{ super(context); }
public SelectAgainSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public SelectAgainSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(this.lastSelected == this.getSelectedItemPosition() && getOnItemSelectedListener() != null)
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), this.getSelectedItemPosition(), getSelectedItemId());
if(!changed)
lastSelected = this.getSelectedItemPosition();
super.onLayout(changed, l, t, r, b);
}
}
최신 플랫폼의 경우 이것을 Dimitar의 솔루션에 추가하십시오. 나는 그것이 작동한다고 생각한다 :)
(onLayout을 재정의하고 onClick 메서드를 제거해야합니다)
@Override
public void onClick(DialogInterface dialog, int which) {
super.onClick(dialog, which);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(this.lastSelected == this.getSelectedItemPosition())
testReflectionForSelectionChanged();
if(!changed)
lastSelected = this.getSelectedItemPosition();
super.onLayout(changed, l, t, r, b);
}
내가 찾은 것은 스피너에서 동일한 항목을 다시 선택하면 OnItemSelectedListener가 호출되지 않는다는 것입니다. 스피너를 클릭하고 동일한 값을 다시 선택하면 OnItemSelectedListener 메서드가 호출되지 않습니다. 사람들은 UI 디자인에 따라 이미 활성화 된 선택 항목을 클릭하면 어떤 일이 일어날 것이라고 기대하지 않습니다.
@Dimitar. 와우, 훌륭한 작품입니다. 감사합니다. 귀하의 솔루션 (포인트가 충분하지 않음)을 찬성 할 수는 없지만 NoDefaultSpinner 클래스가 작동합니다. 이 한 가지만 문제였습니다. "OnClick"내에서 super.onClick을 호출 한 다음 testReflectionForSelectionChanged ()를 호출하기 때문에 선택 항목이 실제로 변경되면 스피너에 대한 onItemSelected 핸들러가 두 번 호출됩니다 (동일한 경우 기능은 올바름). 항목이 다시 선택됨). 나는 그것을 해킹하여 이것을 해결했습니다. 터치 된 항목을 기록한 onTouchEvent 재정의를 추가 한 다음 "onClick"에서 변경되었는지 확인했습니다.
private Object ob=null; //class level variable
@Override
public boolean onTouchEvent(MotionEvent m)
{
if (m.getAction()==MotionEvent.ACTION_DOWN)
{
ob=this.getSelectedItem();
}
return super.onTouchEvent(m);
}
@Override
public void onClick(DialogInterface dialog, int which) {
super.onClick(dialog, which);
if (this.getSelectedItem().equals(ob))
testReflectionForSelectionChanged();
}
이것은 완전한 솔루션은 아니지만 어디서나 조각 / 활동으로 돌아갈 때 이것을 호출하려는 경우에만 작동합니다.
고려 mSpinner 것은 , 우리가 이런 식의 리스너를 호출하여 회 전자이다 :
@Override public void onResume()
{
if ( mSpinner.getCount() > 0 )
{
mSpinner.getOnItemSelectedListener()
.onItemSelected( mSpinner, null, mSpinner.getSelectedItemPosition(), 0 );
}
super.onResume();
}
안녕하세요, 문제에 대한 창의적인 답변에 대해 @Dimitar에게 감사드립니다. 나는 그것을 시도했고 2.x와 같은 이전 Android 버전에서 잘 작동하지만 불행히도 버전 3.0 이상에서는 작동하지 않습니다 (3.2 및 4.0.3 시도). 어떤 이유로 onClick 메서드는 최신 플랫폼에서 호출되지 않습니다. 누군가 여기에 버그 보고서를 작성했습니다. http://code.google.com/p/android/issues/detail?id=16245
최신 플랫폼에서 작동하지 않는다는 것은 다른 솔루션이 필요하다는 것을 의미합니다. 내 응용 프로그램에서는 처음에 숨겨진 "더미"항목이있는 선택되지 않은 스피너를 시뮬레이션하는 것으로 충분했습니다. 그런 다음 "숨겨진"항목이 선택 항목으로 설정된 경우 클릭 된 모든 항목은 콜백을 발생시킵니다. 일부 단점은 아무것도 선택되지 않을 수 있지만 Spinner 클래스 재정의 트릭을 사용하여 수정할 수 있습니다.
Android Spinner에서 한 항목을 숨기는 방법을 참조하세요.
Spinner 동작은 요청에 대해 예상되지 않습니다. 내 솔루션은 Spinner와 함께 작동하지 않습니다. 하나의 BaseFragment 내부에 하나의 ListView를 사용하여 우리가 예상하는 기능을 연구하는 유사한 방식으로 만듭니다.
혜택은 다음과 같습니다.
- Spinner 기본값을 확장하는 데 더 이상 골칫거리가 아닙니다.
- 간편한 구현 및 사용자 정의.
- 모든 Android API와 완벽하게 호환됩니다.
- 첫 번째 OnItemSelectedListener.onItemSelected 호출에 대한 얼굴이 없습니다.
주요 아이디어는 다음과 같이하는 것입니다.
BaseFragment 레이아웃은 다음과 유사합니다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@null"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<ListView
android:id="@+id/fragment_spinnerList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
코드는 다음과 같습니다.
public class SpinnerListFragment extends android.support.v4.app.DialogFragment {
static SpinnerListFragment newInstance(List<String> items) {
SpinnerListFragment spinnerListFragment = new SpinnerListFragment();
Bundle args = new Bundle();
args.putCharSequenceArrayList("items", (ArrayList) items);
spinnerListFragment.setArguments(args);
return spinnerListFragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(getActivity(), R.style.dialog);
final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_spinner_list, null);
dialog.getWindow().setContentView(view);
dialog.setCanceledOnTouchOutside(true);
// CUSTOMIZATION...
final List items = (ArrayList) getArguments().getCharSequenceArrayList("items");
final ListView spinnerList = (ListView) view.findViewById(R.id.fragment_spinnerList);
ArrayAdapter<String> arrayAdapter =
new ArrayAdapter<String>(
getActivity(),
R.layout.search_spinner_list_item,
items);
spinnerList.setAdapter(arrayAdapter);
spinnerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// DO SOMETHING...
SpinnerListFragment.this.dismiss();
}
});
return dialog;
}
}
내 솔루션은 benoffi7의 MySpinner를 기반으로합니다. 마지막으로 선택한 상위 및보기를 저장하여 동일한 항목 선택에서 null 전달을 수정합니다.
public class MySpinner extends Spinner {
private OnItemSelectedListener listener;
private AdapterView<?> lastParent;
private View lastView;
private long lastId;
public MySpinner(Context context, AttributeSet attrs) {
super(context, attrs);
initInternalListener();
}
public MySpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initInternalListener();
}
private void initInternalListener() {
super.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
lastParent = parent;
lastView = view;
lastId = id;
if (listener != null) {
listener.onItemSelected(parent, view, position, id);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
//lastParent = parent; // do we need it?
if (listener != null) {
listener.onNothingSelected(parent);
}
}
});
}
@Override
public void setSelection(int position) {
if (position == getSelectedItemPosition() && listener != null) {
listener.onItemSelected(lastParent, lastView, position, lastId);
} else {
super.setSelection(position);
}
}
@Override
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
this.listener = listener;
}
}
class MySpinner extends Spinner {
public MySpinner(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MySpinner(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
public void setSelection(int position, boolean animate) {
ignoreOldSelectionByReflection();
super.setSelection(position, animate);
}
private void ignoreOldSelectionByReflection() {
try {
Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();
Field reqField = c.getDeclaredField("mOldSelectedPosition");
reqField.setAccessible(true);
reqField.setInt(this, -1);
} catch (Exception e) {
Log.d("Exception Private", "ex", e);
// TODO: handle exception
}
}
@Override
public void setSelection(int position) {
ignoreOldSelectionByReflection();
super.setSelection(position);
}
}
다음과 같이 "onTouch"를 기반으로 프로그래밍 방식으로 "선택된 항목"을 설정할 수 있기 때문에 쉬운 해결책이 있습니다.
spinnerobject.setOnTouchListener(new AdapterView.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
final int MAKE_A_SELECTION = 1; //whatever index that is the normal starting point of the spinner.
spinnerObject.setSelection(MAKE_A_SELECTION);
return false;
}
});
(1) 스피너 행이 표시되기 직전에 스피너 텍스트가 기본값으로 다시 변경되고 (2)이 기본 항목이 목록의 일부가된다는 점에서 작은 패널티가 있습니다. 누군가가 스피너의 특정 항목을 비활성화하는 방법을 추가 할 수 있습니까?
일반적으로 스피너 선택은 검색 시작과 같은 반복 가능한 이벤트를 실행할 수 있기 때문에 스피너에서 항목을 다시 선택할 가능성이 없다는 것은 실제로 Spinner 클래스에서 누락 된 기능 / 버그이며 Android 개발자가 최대한 빨리 수정해야하는 버그입니다. .
안녕하세요, 이것은 나를 위해 일했습니다.
ArrayAdapter<String> adaptador1 = new ArrayAdapter<String>( Ed_Central.this,
android.R.layout.simple_spinner_item,
datos1
);
lista1.setAdapter( adaptador1 );
lista1.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected( AdapterView<?> parent, View view, int position, long id ) {
lista1.setSelection( 0 );
switch ( position ) {
case 1:
Toast.makeText( getApplicationContext(), "msg1", Toast.LENGTH_SHORT ).show();
break;
case 2:
Toast.makeText( getApplicationContext(), "msg2", Toast.LENGTH_SHORT ).show();
break;
case 3:
Toast.makeText( getApplicationContext(), "msg3", Toast.LENGTH_SHORT ).show();
break;
default:
break;
}
}
항상 어댑터는 위치 "0"에있을 것이고 토스트를 보여줄 수 있습니다.
스피너 디스플레이가 하나의 편집 텍스트를 추가하고 가시성 사라진 속성을 설정할 때 XML에서이 작업을 정말로 수행하려는 경우; spinner 및 view.onclicklisner에 설정된 의상 어댑터에 대한 의상 어댑터를 만들고 clickevent가 발생했을 때 EditText.setText ( "0"); 활동 세트 edittext textWatcher Event 및 이벤트 블록에서 onSppinerItem 이벤트 블록 코드를 추가합니다. 문제 해결
package customclasses;
/**
* Created by Deepak on 7/1/2015.
*/
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
/**
* Spinner extension that calls onItemSelected even when the selection is the same as its previous value
*/
public class NDSpinner extends Spinner {
public boolean isDropDownMenuShown=false;
public NDSpinner(Context context) {
super(context);
}
public NDSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NDSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@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 boolean performClick() {
this.isDropDownMenuShown = true; //Flag to indicate the spinner menu is shown
return super.performClick();
}
public boolean isDropDownMenuShown(){
return isDropDownMenuShown;
}
public void setDropDownMenuShown(boolean isDropDownMenuShown){
this.isDropDownMenuShown=isDropDownMenuShown;
}
@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());
}
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
Custom spinner with same item selection callback in Kotlin:
class StorageSpinner : AppCompatSpinner {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
interface StorageSpinnerSelectionCallback {
fun onItemSelected(position: Int)
}
private var selectionCallback: StorageSpinnerSelectionCallback? = null
fun setSelectionCallback(selectionCallback: StorageSpinnerSelectionCallback) {
this.selectionCallback = selectionCallback
}
fun removeSelectionCallback() {
selectionCallback = null
}
override fun setSelection(position: Int) {
super.setSelection(position)
if (position == selectedItemPosition) selectionCallback?.onItemSelected(position)
}
}
You must perform the following steps: 1. Create an Adapter Customer for the spinner 2. In the override fun getDropDownView (...), you must put a view.setOnClickListener {"interface"} 3. Create an interface
Try this, this might be not the proper solution but is the best working solution available right now, if not making a custom spinner.
what you have to do is to reset spinner adapter on every item click,
@Override
public void onItemSelected(AdapterView adapter, View v, int position, long lng) {
if (position == getSelectedItemPosition())
{
//do your thing
//then at end of statement reset adapter like
spinner.setAdapter(adapter);
}
}
I hope it helped you solve your problem
Continue from this answer https://stackoverflow.com/a/17099104/7392507
In your xml file, create a spinner. Replace the spinner tag <Spinner>
with <yourdomain.yourprojectname.yourpackagename.spinnerclassname>
for example <com.company.appname.utility.MySpinner>
.
In your java file, define the spinner variable as below: -Spinnerclassname varName = findViewById(R.id.spinnerId);
For example: -MySpinner varSpinner = findViewById(R.id.spinnerId);
Just try out with this.
@Override
public void onItemSelected(AdapterView adapter, View v, int i, long lng) {
if(v.hasFocus() {
Toast.makeText(getApplicationContext(), (CharSequence) StorageSpinner.getSelectedItem(), Toast.LENGTH_SHORT).show();
}
}
Hope it may work.
ReferenceURL : https://stackoverflow.com/questions/5335306/how-can-i-get-an-event-in-android-spinner-when-the-current-selected-item-is-sele
'developer tip' 카테고리의 다른 글
C #에서 모든 컨트롤러 및 작업 이름 가져 오기 (0) | 2021.01.05 |
---|---|
Python : ( "hello"는 "hello")가 True로 평가되는 이유는 무엇입니까? (0) | 2021.01.05 |
MySQL의 Case 문 (0) | 2021.01.05 |
PHP 용 AWS SDK : 인스턴스 프로필 메타 데이터 서버에서 자격 증명을 검색하는 동안 오류가 발생했습니다. (0) | 2021.01.05 |
세션에서 항목을 제거하는 ASP.NET? (0) | 2021.01.05 |