I have written an setOnItemSelectedListener for spinner to respond when the spinner item is changed. My requirement is when I clicks again the currently selected item, a toast should display. How to get this event? When the currently selected item is clicked again, spinner is not responding. `
我已经为spinner编写了一个setOnItemSelectedListener,以便在spinner项发生更改时作出响应。我的要求是当我再次单击当前选中的项目时,应该显示一个吐司。如何获得这个事件?当再次单击当前选中的项时,spinner没有响应。”
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();
}
});
18 个解决方案
#1
-12
When you clicks again the currently selected item, then it can not fire any event. So you can not catch setOnItemSelectedListener for spinner to respond.
当您再次单击当前选中的项目时,它将无法触发任何事件。因此您无法捕获setOnItemSelectedListener以便spinner作出响应。
#2
98
I spent a good few hours trying to get something to solve this problem. I ended up with the following. I'm not certain if it works in all cases, but it seems to work for me. It's just an extension of the Spinner class which checks the selection and calls the listener if the selection is set to the same value.
我花了好几个小时试图找到解决这个问题的办法。我得到了下面的结果。我不确定它是否在所有情况下都有效,但它似乎对我有效。它只是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());
}
}
}
#3
21
try this
试试这个
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;
}
}
#4
14
This spinner will always tell you that selection has changed:
这个旋转器会告诉你,选择已经改变了:
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;
}
}
#5
5
I figured I'd leave an updated answer for those working on newer Android versions.
我想我应该给那些使用新Android版本的人留下一个更新的答案。
I compiled together a function from the above answers that will work for at least 4.1.2 and 4.3 (the devices I tested on). This function doesn't use reflection, but instead tracks the last selected index itself, so should be safe to use even if the SDK changes how the classes extend each other.
我根据上面的答案编译了一个函数,这个函数至少适用于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);
}
}
#6
4
for newer platforms try to add this to Dimitar's solution. I think it works :)
对于较新的平台,尝试将其添加到Dimitar的解决方案中。我认为它是有效的
(you have to override onLayout and to remove onClick method)
(必须重写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);
}
#7
3
What I found is, OnItemSelectedListener won't be called if the same item is selected again in a spinner. When i click on spinner and again select the same value, then OnItemSelectedListener method is not called. People do not expect something to happen if they click on a selection that is already active as per the UI design.
我发现,如果在spinner中再次选择相同的项,OnItemSelectedListener将不会被调用。当我单击spinner并再次选择相同的值时,则不会调用OnItemSelectedListener方法。如果按UI设计单击已经激活的选项,人们不会期望发生什么事情。
#8
2
@Dimitar. WOW, brilliant work. Thanks for that. I can't upvote your solution (not enough points) but the NoDefaultSpinner class WORKS. Only this one thing was a problem: because you call super.onClick and then testReflectionForSelectionChanged() inside "OnClick", you will get the onItemSelected handler for the spinner being called twice if the selection DOES actually change (while functionality is correct if the same item is re-selected). I solved this by hacking around it. I added an onTouchEvent override that recorded which item was touched, then checked if this had changed in "onClick":
@Dimitar。哇,出色的工作。谢谢你,。我不能支持你的解决方案(没有足够的分数),但是NoDefaultSpinner类可以工作。唯一的问题是:因为你叫super。onClick然后在“onClick”中testReflectionForSelectionChanged()中,如果选择确实发生更改,您将获得被调用两次的微调器的onItemSelected处理程序(如果重新选择相同的项,则功能是正确的)。我用黑客技术解决了这个问题。我添加了一个onTouchEvent override,记录了被触摸的项,然后检查它是否在“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();
}
#9
1
Hello & thanks @Dimitar for a creative answer to the problem. I've tried it and it works well on older Android versions like 2.x, but unfortunately it doesn't work on version 3.0 and later (tried 3.2 and 4.0.3). For some reason the onClick method is never called on newer platforms. Someone has written a bug report for this here: http://code.google.com/p/android/issues/detail?id=16245
你好,感谢@Dimitar对这个问题的创造性回答。我已经试过了,它在像2这样的老版本上运行得很好。但不幸的是,它不能在3.0和以后的版本中工作(尝试了3.2和4.0.3)。出于某种原因,onClick方法不会在更新的平台上调用。有人为此写了一个bug报告:http://code.google.com/p/android/issues/detail?id=16245
Not functioning on newer platforms means I needed a different solution. In my application it was sufficient to simulate an unselected spinner with a hidden "dummy" entry at the start. Then every item clicked will result in a callback if the "hidden" item is set as the selection. A drawback for some may be that nothing will appear selected, but that could be fixed using Spinner class override tricks.
不能在新平台上运行意味着我需要一个不同的解决方案。在我的应用程序中,只要在开始时使用隐藏的“虚拟”条目来模拟一个未选中的微调器就足够了。然后,如果将“隐藏”项设置为选择项,则单击的每一个项都会产生回调。对有些人来说,一个缺点可能是没有出现被选中,但是可以使用Spinner类覆盖技巧来修复。
See How to hide one item in an Android Spinner
查看如何在Android微调器中隐藏一个项目
#10
1
The Spinner behaviour is not expected for our requeriments. My solution is not work with Spinners, make it in one similar way, with one ListView inside one BaseFragment to research the functionality we are expected.
对于我们的请求者来说,不期望出现Spinner行为。我的解决方案不是使用旋转器,而是使用类似的方式,在一个BaseFragment中使用一个ListView来研究我们期望的功能。
The beneficts are:
beneficts有:
- No more headaches extending Spinner defaults.
- 不再有扩展Spinner默认值的头痛。
- Easy implementation and customization.
- 容易实现和定制。
- Full compatibility along all Android APIs.
- 完全兼容所有Android api。
- No face against first OnItemSelectedListener.onItemSelected call.
- 没有面对第一个OnItemSelectedListener。onItemSelected电话。
The main idea, is do something like this:
主要的想法是,做这样的事情:
The BaseFragment layout could looks similar to:
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>
The code looks something like this:
代码看起来是这样的:
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;
}
}
#11
1
My solution is Based on MySpinner by benoffi7. Fixes passing nulls on same item selection by saving the last selected parent and view.
我的解决办法是基于我的内心。通过保存最后选中的父视图,修复在相同项选择上传递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;
}
}
#12
1
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);
}
}
#13
1
This is not full solution but it works if you only want to call this when you're getting back to your fragment/activity from wherever.
这不是完整的解决方案,但是如果您只想在从任何地方返回片段/活动时调用它,那么它就可以工作。
Considering mSpinner is your Spinner view, we call it's listener like this:
考虑到mSpinner是你的Spinner视图,我们称它为监听器:
@Override public void onResume()
{
if ( mSpinner.getCount() > 0 )
{
mSpinner.getOnItemSelectedListener()
.onItemSelected( mSpinner, null, mSpinner.getSelectedItemPosition(), 0 );
}
super.onResume();
}
#14
1
This has an easy solution because it is possible to set the "selected item" programmatically based on "onTouch", like this:
这有一个简单的解决方案,因为可以根据“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;
}
});
There is a tiny penalty in that (1) the spinner text will change back to the default just prior to the spinner rows being displayed, and (2), this default item will be part of the list. Perhaps someone can add how to disable a particular item for a spinner?
在(1)spinner文本将在显示spinner行之前更改为默认值,而(2)这个默认项将是列表的一部分。也许有人可以添加如何禁用一个特定项目的转轮?
Generally speaking, since a spinner selection may execute a repeatable event (like starting a search), the lack of possibility to reselect an item in a spinner is really a missing feature/bug in the Spinner class, a bug that Android developers should correct ASAP.
一般来说,由于spinner选择可能执行一个可重复的事件(如开始搜索),所以在spinner类中缺少重新选择项的可能性实际上是spinner类中缺少的特性/bug, Android开发人员应该尽快纠正这个bug。
#15
1
Hi man, this worked for me:
嗨,伙计,这对我很管用:
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;
}
}
Always the adapter is going to be at position "0", and you can show your toast.
适配器总是位于“0”位置,您可以展示您的吐司。
#16
0
if u really want to do this task in your XML when your spinner display add one edit text and set visibility gone attribute; and create costume adapter for spinner and in costume adapter set on view.onclicklisner and when clickevent fired EditText.setText("0"); and in activity set edittext textWatcher Event and in event block you add your onSppinerItem Event Block code; Your Problem Solved
如果你真的想要在你的XML中做这个任务,当你的spinner显示添加一个编辑文本并设置可视性消失属性;并为旋转器创建服装适配器,并在视图中设置服装适配器。onclicklisner和当clickevent触发EditText.setText(“0”);在活动设置edittext textWatcher事件中,在事件块中添加onSppinerItem事件块代码;你的问题解决了
#17
0
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();
}
}
#18
-1
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.
希望它可以工作。
#1
-12
When you clicks again the currently selected item, then it can not fire any event. So you can not catch setOnItemSelectedListener for spinner to respond.
当您再次单击当前选中的项目时,它将无法触发任何事件。因此您无法捕获setOnItemSelectedListener以便spinner作出响应。
#2
98
I spent a good few hours trying to get something to solve this problem. I ended up with the following. I'm not certain if it works in all cases, but it seems to work for me. It's just an extension of the Spinner class which checks the selection and calls the listener if the selection is set to the same value.
我花了好几个小时试图找到解决这个问题的办法。我得到了下面的结果。我不确定它是否在所有情况下都有效,但它似乎对我有效。它只是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());
}
}
}
#3
21
try this
试试这个
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;
}
}
#4
14
This spinner will always tell you that selection has changed:
这个旋转器会告诉你,选择已经改变了:
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;
}
}
#5
5
I figured I'd leave an updated answer for those working on newer Android versions.
我想我应该给那些使用新Android版本的人留下一个更新的答案。
I compiled together a function from the above answers that will work for at least 4.1.2 and 4.3 (the devices I tested on). This function doesn't use reflection, but instead tracks the last selected index itself, so should be safe to use even if the SDK changes how the classes extend each other.
我根据上面的答案编译了一个函数,这个函数至少适用于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);
}
}
#6
4
for newer platforms try to add this to Dimitar's solution. I think it works :)
对于较新的平台,尝试将其添加到Dimitar的解决方案中。我认为它是有效的
(you have to override onLayout and to remove onClick method)
(必须重写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);
}
#7
3
What I found is, OnItemSelectedListener won't be called if the same item is selected again in a spinner. When i click on spinner and again select the same value, then OnItemSelectedListener method is not called. People do not expect something to happen if they click on a selection that is already active as per the UI design.
我发现,如果在spinner中再次选择相同的项,OnItemSelectedListener将不会被调用。当我单击spinner并再次选择相同的值时,则不会调用OnItemSelectedListener方法。如果按UI设计单击已经激活的选项,人们不会期望发生什么事情。
#8
2
@Dimitar. WOW, brilliant work. Thanks for that. I can't upvote your solution (not enough points) but the NoDefaultSpinner class WORKS. Only this one thing was a problem: because you call super.onClick and then testReflectionForSelectionChanged() inside "OnClick", you will get the onItemSelected handler for the spinner being called twice if the selection DOES actually change (while functionality is correct if the same item is re-selected). I solved this by hacking around it. I added an onTouchEvent override that recorded which item was touched, then checked if this had changed in "onClick":
@Dimitar。哇,出色的工作。谢谢你,。我不能支持你的解决方案(没有足够的分数),但是NoDefaultSpinner类可以工作。唯一的问题是:因为你叫super。onClick然后在“onClick”中testReflectionForSelectionChanged()中,如果选择确实发生更改,您将获得被调用两次的微调器的onItemSelected处理程序(如果重新选择相同的项,则功能是正确的)。我用黑客技术解决了这个问题。我添加了一个onTouchEvent override,记录了被触摸的项,然后检查它是否在“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();
}
#9
1
Hello & thanks @Dimitar for a creative answer to the problem. I've tried it and it works well on older Android versions like 2.x, but unfortunately it doesn't work on version 3.0 and later (tried 3.2 and 4.0.3). For some reason the onClick method is never called on newer platforms. Someone has written a bug report for this here: http://code.google.com/p/android/issues/detail?id=16245
你好,感谢@Dimitar对这个问题的创造性回答。我已经试过了,它在像2这样的老版本上运行得很好。但不幸的是,它不能在3.0和以后的版本中工作(尝试了3.2和4.0.3)。出于某种原因,onClick方法不会在更新的平台上调用。有人为此写了一个bug报告:http://code.google.com/p/android/issues/detail?id=16245
Not functioning on newer platforms means I needed a different solution. In my application it was sufficient to simulate an unselected spinner with a hidden "dummy" entry at the start. Then every item clicked will result in a callback if the "hidden" item is set as the selection. A drawback for some may be that nothing will appear selected, but that could be fixed using Spinner class override tricks.
不能在新平台上运行意味着我需要一个不同的解决方案。在我的应用程序中,只要在开始时使用隐藏的“虚拟”条目来模拟一个未选中的微调器就足够了。然后,如果将“隐藏”项设置为选择项,则单击的每一个项都会产生回调。对有些人来说,一个缺点可能是没有出现被选中,但是可以使用Spinner类覆盖技巧来修复。
See How to hide one item in an Android Spinner
查看如何在Android微调器中隐藏一个项目
#10
1
The Spinner behaviour is not expected for our requeriments. My solution is not work with Spinners, make it in one similar way, with one ListView inside one BaseFragment to research the functionality we are expected.
对于我们的请求者来说,不期望出现Spinner行为。我的解决方案不是使用旋转器,而是使用类似的方式,在一个BaseFragment中使用一个ListView来研究我们期望的功能。
The beneficts are:
beneficts有:
- No more headaches extending Spinner defaults.
- 不再有扩展Spinner默认值的头痛。
- Easy implementation and customization.
- 容易实现和定制。
- Full compatibility along all Android APIs.
- 完全兼容所有Android api。
- No face against first OnItemSelectedListener.onItemSelected call.
- 没有面对第一个OnItemSelectedListener。onItemSelected电话。
The main idea, is do something like this:
主要的想法是,做这样的事情:
The BaseFragment layout could looks similar to:
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>
The code looks something like this:
代码看起来是这样的:
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;
}
}
#11
1
My solution is Based on MySpinner by benoffi7. Fixes passing nulls on same item selection by saving the last selected parent and view.
我的解决办法是基于我的内心。通过保存最后选中的父视图,修复在相同项选择上传递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;
}
}
#12
1
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);
}
}
#13
1
This is not full solution but it works if you only want to call this when you're getting back to your fragment/activity from wherever.
这不是完整的解决方案,但是如果您只想在从任何地方返回片段/活动时调用它,那么它就可以工作。
Considering mSpinner is your Spinner view, we call it's listener like this:
考虑到mSpinner是你的Spinner视图,我们称它为监听器:
@Override public void onResume()
{
if ( mSpinner.getCount() > 0 )
{
mSpinner.getOnItemSelectedListener()
.onItemSelected( mSpinner, null, mSpinner.getSelectedItemPosition(), 0 );
}
super.onResume();
}
#14
1
This has an easy solution because it is possible to set the "selected item" programmatically based on "onTouch", like this:
这有一个简单的解决方案,因为可以根据“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;
}
});
There is a tiny penalty in that (1) the spinner text will change back to the default just prior to the spinner rows being displayed, and (2), this default item will be part of the list. Perhaps someone can add how to disable a particular item for a spinner?
在(1)spinner文本将在显示spinner行之前更改为默认值,而(2)这个默认项将是列表的一部分。也许有人可以添加如何禁用一个特定项目的转轮?
Generally speaking, since a spinner selection may execute a repeatable event (like starting a search), the lack of possibility to reselect an item in a spinner is really a missing feature/bug in the Spinner class, a bug that Android developers should correct ASAP.
一般来说,由于spinner选择可能执行一个可重复的事件(如开始搜索),所以在spinner类中缺少重新选择项的可能性实际上是spinner类中缺少的特性/bug, Android开发人员应该尽快纠正这个bug。
#15
1
Hi man, this worked for me:
嗨,伙计,这对我很管用:
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;
}
}
Always the adapter is going to be at position "0", and you can show your toast.
适配器总是位于“0”位置,您可以展示您的吐司。
#16
0
if u really want to do this task in your XML when your spinner display add one edit text and set visibility gone attribute; and create costume adapter for spinner and in costume adapter set on view.onclicklisner and when clickevent fired EditText.setText("0"); and in activity set edittext textWatcher Event and in event block you add your onSppinerItem Event Block code; Your Problem Solved
如果你真的想要在你的XML中做这个任务,当你的spinner显示添加一个编辑文本并设置可视性消失属性;并为旋转器创建服装适配器,并在视图中设置服装适配器。onclicklisner和当clickevent触发EditText.setText(“0”);在活动设置edittext textWatcher事件中,在事件块中添加onSppinerItem事件块代码;你的问题解决了
#17
0
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();
}
}
#18
-1
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.
希望它可以工作。