2010-04-14 104 views
22

的OnItemSelectedListener事件处理函数被调用时,都一个微调 编程方式更改选定,当用户物理点击微调控制。 是否可以确定某个事件是否由用户以某种方式选择了 ?Android的微调选择

或者还有另一种方式来处理微调器的用户选择?

+0

这为我工作 与设置中选择可运行 http://stackoverflow.com/a/13528576/1104279 – Gil 2013-01-20 09:09:25

回答

49

要解决您的问题,您需要记住上次选择的位置。然后在你的微调监听器里面比较最后选择的位置和新的位置。如果它们不同,则处理该事件并且还用新的位置值更新最后选择的位置,否则就跳过事件处理。

如果代码中的某处您将以编程方式更改微调器选定位置,并且您不希望侦听器处理该事件,那么只需将最后选定的位置重置为您要设置的位置。

是的,在Android的微调是痛苦的。我甚至会说疼痛从名字开始 - “微调”。这是否有点误导? :)就我们正在谈论它而言,您还应该意识到存在一个错误 - 微调器可能无法恢复(并非总是)其状态(在设备旋转时),因此请确保您手动处理微调器的状态。

+0

如果用户想要在位置0选择项目该怎么办?据我了解你的解决方案,它将被忽略 – 2016-11-14 16:45:18

+0

@NicolásCarrasco,这是6年前..我根本无法回想上下文,但肯定我没有解决方案的问题。可能考虑使用-1作为最后选定位置的起始值。 – 2016-11-16 16:24:32

+0

如果您将该值作为-1开始,那么当Spinner布局时,将以position = 0作为参数调用监听器。当然-1!= 0,所以事件会触发,这个问题上提到的问题仍然没有解决。我不想暗示你的答案是错误的,但它不完整 – 2016-11-18 17:18:24

2

在过去,我已经做了这样的事情来区分

internal++; // 'internal' is an integer field initialized to 0 
textBox.setValue("...."); // listener should not act on this internal setting 
internal--; 

然后在文本框的听众

if (internal == 0) { 
    // ... Act on user change action 
} 

我使用++和 - 而不是一个布尔值设置为“真'这样当方法嵌套也可能设置内部更改指示符的其他方法时,不必担心。

+6

它不能在微调工作,因为onItemSelected方法在调度相应事件时异步调用。 – Arutha 2010-04-14 12:17:09

20

很难相信,一年半后,问题依然存在,并继续惊奇的人...

想我会分享我阅读Arhimed最有用的帖子后,想出了变通办法(感谢,我同意纺纱厂痛苦!)。我一直在做,以避免这些误报是使用一个简单的包装类:对于已经选择了相同的位置

import android.util.Log; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemSelectedListener; 

public class OnItemSelectedListenerWrapper implements OnItemSelectedListener { 

    private int lastPosition; 
    private OnItemSelectedListener listener; 

    public OnItemSelectedListenerWrapper(OnItemSelectedListener aListener) { 
     lastPosition = 0; 
     listener = aListener; 
    } 

    @Override 
    public void onItemSelected(AdapterView<?> aParentView, View aView, int aPosition, long anId) { 
     if (lastPosition == aPosition) { 
      Log.d(getClass().getName(), "Ignoring onItemSelected for same position: " + aPosition); 
     } else { 
      Log.d(getClass().getName(), "Passing on onItemSelected for different position: " + aPosition); 
      listener.onItemSelected(aParentView, aView, aPosition, anId); 
     } 
     lastPosition = aPosition; 
    } 

    @Override 
    public void onNothingSelected(AdapterView<?> aParentView) { 
     listener.onNothingSelected(aParentView); 
    } 
} 

它所做的就是陷阱的项目选择事件(如初始自动触发选择位置0),并将其他事件传递给包装好的侦听器。要使用它,你所要做的就是修改代码调用听者包括包装线(并添加当然右括号),所以不是,说:

mySpinner.setOnItemSelectedListener(new OnItemSelectedListener() { 
    ... 
}); 

你会有这样的:

mySpinner.setOnItemSelectedListener(new OnItemSelectedListenerWrapper(new OnItemSelectedListener() { 
    ... 
})); 

显然,一旦你测试过它,你可以摆脱登录的电话,你可以添加重置最后一个位置的能力,如果需要的话(你必须保持一个参考这个例子当然不是在即时宣布),正如Arhimed所说的那样。

希望这可以帮助从这种奇怪的行为;-)

1

我也看了在互联网上的一个很好的解决方案,但没有发现任何满足我的需求所驱动的疯狂的人。 所以我在Spinner类中编写了这个扩展,所以你可以设置一个简单的OnItemClickListener,它具有与ListView相同的行为。

只有当某个项目被选中时,onItemClickListener才会被调用。

玩得开心!

public class MySpinner extends Spinner 
    { 
     private OnItemClickListener onItemClickListener; 


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

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

     public MySpinner(Context context, AttributeSet attrs, int defStyle) 
     { 
      super(context, attrs, defStyle); 
     } 

     @Override 
     public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener inOnItemClickListener) 
     { 
      this.onItemClickListener = inOnItemClickListener; 
     } 

     @Override 
     public void onClick(DialogInterface dialog, int which) 
     { 
      super.onClick(dialog, which); 

      if (this.onItemClickListener != null) 
      { 
       this.onItemClickListener.onItemClick(this, this.getSelectedView(), which, this.getSelectedItemId()); 
      } 
     } 
    } 
0

我做了一些日志记录,发现它只能在初始化时调用,这很烦人。看不到所有这些代码的需要,我刚刚创建了一个实例变量,该实例变量被初始化为一个保护值,然后在该方法第一次被调用后进行设置。

我记录了onItemSelected方法被调用时,否则只会被调用一次。

我在创建两件东西时遇到了问题,并且意识到这是因为我在我的定制适配器上调用了add(),该定制适配器已经引用了我所引用的列表并且已添加到适配器外部。在我意识到这一点并删除了添加方法后,问题就消失了。

你们是否确定你需要所有这些代码?

1

只是为了扩大上面的aaamos的帖子,因为我没有50个代表点评,我在这里创建一个新的答案。

基本上,他的代码适用的情况下,当最初的微调选择为0,但概括它,我修改了他的代码的方式如下:

@Override 
public void setOnItemSelectedListener(final OnItemSelectedListener listener) 
{ 
    if (listener != null) 
     super.setOnItemSelectedListener(new OnItemSelectedListener() 
     { 
      private static final int NO_POSITION = -1; 

      private int lastPosition = NO_POSITION; 


      @Override 
      public void onItemSelected(AdapterView<?> parent, View view, int position, long id) 
      { 
       if ((lastPosition != NO_POSITION) && (lastPosition != position)) 
        listener.onItemSelected(parent, view, position, id); 

       lastPosition = position; 
      } 


      @Override 
      public void onNothingSelected(AdapterView<?> parent) 
      { 
       listener.onNothingSelected(parent); 
      } 
     }); 
    else 
     super.setOnItemSelectedListener(null); 
} 

基本上,此代码将忽略第一个发射onItemSelected(),然后是所有后续的“相同位置”调用。

当然,这里的要求是选择设定编程,但应该无论如何是如果默认的位置不为0

2

我用纺纱的时候出现过这种情况最近和互联网没”提出了一个合适的解决方案。

我的应用场景:

X纺纱(动态,2为每个CPU,最小&最大值)设定&观看CPU频。它们在应用程序启动时被填充,并且它们也获得cpu集的当前最大/最小频率。线程在后台运行并每秒检查一次更改并相应更新调整器。如果用户设置了微调器内部的新频率,则设置新的频率。

问题是,线程访问setSelection来更新当前的频率,然后又调用我的监听器,我无法知道它是否是用户或线程改变了值。如果是线程,我不希望监听器被调用,因为不需要改变频率。

我想出了完美的适合我的需要和周围的听众适用于您的电话:)(我认为这个解决方案为您提供了最大的控制)

我伸出微调的解决方案:

import android.content.Context; 
import android.widget.Spinner; 

public class MySpinner extends Spinner { 
    private boolean call_listener = true; 

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

    public boolean getCallListener() { 
     return call_listener; 
    } 

    public void setCallListener(boolean b) { 
     call_listener = b; 
    } 

    @Override 
    public void setSelection(int position, boolean lswitch) { 
     super.setSelection(position); 
     call_listener = lswitch; 
    } 
} 

,并创建了自己的OnItemSelectedListener:

import android.util.Log; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemSelectedListener; 

public class SpinnerOnItemSelectedListener implements OnItemSelectedListener { 
     public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) { 
      MySpinner spin = (MySpinner) parent.findViewById(parent.getId()); 
      if (!spin.getCallListener()) { 
       Log.w("yourapptaghere", "Machine call!"); 
       spin.setCallListener(true); 
      } else { 
       Log.w("yourapptaghere", "UserCall!"); 
      } 
     } 

     @Override 
     public void onNothingSelected(AdapterView<?> arg0) { 
     // TODO Auto-generated method stub 
     } 
} 

如果您现在就创建您可以使用此设置选择一个MySpinner:

setSelection(position, callListener);

其中callListener为true或false。 True会调用监听器并且是默认的,这就是为什么用户交互被识别的原因,false也会调用监听器,但是使用你想要的代码来处理这个特殊情况,例如我的情况:Nothing。

我希望别人发现这个有用的,并不遗余力一个漫长的旅程,看,如果这样的事情已经存在:)

0

我知道这是相当晚了,但我想出了一个非常简单的解决这个。它基于Arhimed的回答,完全一样。这也很容易实现。请参阅接受的答案:

Undesired onItemSelected calls