当再次select当前所选项目时,如何在Android微调器中获取事件?

我已经写了一个setOnItemSelectedListener让微调框在微调项目被改变时作出响应。 我的要求是当我再次点击当前select的项目时,应该显示敬酒。 如何得到这个事件? 当再次点击当前select的项目时,微调器没有响应。 `

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类的一个扩展,如果select设置为相同的值,它将检查select并调用侦听器。

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

这个微调将总是告诉你,select已经改变:

 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版本上工作的人留下一个更新的答案。

我从上面的答案编译了一个函数,这个函数至less可以在4.1.2和4.3(我testing过的设备)上工作。 这个函数不使用reflection,而是跟踪最后select的索引本身,所以即使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的解决scheme。 我认为它的作品:)

(你必须重写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); } 

我发现,如果在微调器中再次select了相同的项目,OnItemSelectedListener将不会被调用。 当我单击微调,然后再次select相同的值,则不会调用OnItemSelectedListener方法。 如果按照UIdevise点击已经激活的选项,人们不会期望发生什么事情。

@Dimitar。 哇,精彩的工作。 感谢那。 我不能upvote你的解决scheme(没有足够的分数),但NoDefaultSpinner类工程。 只有这一件事是一个问题:因为你在“OnClick”中调用super.onClick然后testReflectionForSelectionChanged(),如果select确实会改变,你将得到两次被调用的微调控件的onItemSelected处理程序(如果function正确项目被重新select)。 我通过黑客来解决这个问题。 我添加了一个onTouchEvent覆盖,logging哪个项目被触摸,然后检查这是否在“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(); } 

你好,感谢@Dimitar对这个问题的创造性回答。 我已经尝试过了,它可以在较旧的Android版本(例如2.x)上运行良好,但不幸的是,它在V3.0及更高版本(尝试3.2和4.0.3)上无法运行。 出于某种原因,onClick方法从不在新平台上调用。 有人为此写了一个错误报告: http : //code.google.com/p/android/issues/detail?id=16245

在新平台上运行意味着我需要一个不同的解决scheme。 在我的应用程序中,一开始就用一个隐藏的“虚拟”条目来模拟一个未被选中的微调器就足够了。 然后,如果将“隐藏”项目设置为选项,则每个点击的项目都会导致callback。 一些缺点可能是没有select,但可以使用微调类替代技巧修复。

请参阅如何隐藏Android微调器中的一个项目

Spinner的行为不适用于我们的要求。 我的解决scheme不适用于Spinners,使用一个类似的方法,在一个BaseFragment中使用一个ListView来研究我们所期待的function。

好处是:

  1. 没有更多的麻烦延伸Spinner默认。
  2. 易于实施和定制。
  3. 完全兼容所有Android API。
  4. 没有面对第一个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; } } 

我的解决scheme是基于Benoffi7的MySpinner。 修复通过保存最后select的父项和视图在相同的项目select上传递空值。

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

这不是完整的解决scheme,但是如果你只是想在你从任何地方回到你的片段/活动时调用这个解决scheme的话。

考虑到mSpinner是你的Spinner视图,我们把它称为监听器:

 @Override public void onResume() { if ( mSpinner.getCount() > 0 ) { mSpinner.getOnItemSelectedListener() .onItemSelected( mSpinner, null, mSpinner.getSelectedItemPosition(), 0 ); } super.onResume(); } 

这有一个简单的解决scheme,因为可以基于“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),这个默认项目将成为列表的一部分。 也许有人可以添加如何禁用微调的特定项目?

一般来说,由于微调select可能会执行一个可重复的事件(比如开始search),重新select微调项目的可能性的缺失实际上是Spinner类中缺less的特性/缺陷,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中做这个任务,当你的微调显示添加一个编辑文本,并设置可见性消失的属性; 并创build服装适配器的微调和服装适配器设置view.onclicklisner和当clickevent发射EditText.setText(“0”); 并在活动设置edittext textWatcher事件和事件块中添加您的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(); } } 

试试这个。

 @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(); } } 

希望它可以工作。