2010-02-19 36 views
28

想知道如何处理以下问题:根据两个spinners的选定项目计算结果。为了处理UI事情,即用户在其中一个spinners中选择一个新项目,我在该活动的onCreate()方法中安装了一个使用setOnItemSelectedListener作为微调器的侦听器。如何通过代码设置所选项目时禁用onItemSelectedListener

现在:那工作,当然很好。听众的工作是触发结果的新计算。

的问题:因为我拦截onPause()onResume()保存/恢复过去的状态,我有一个方法这两个微调选定的项目编程就像在这里:

startSpinner.setSelection(pStart); 
destSpinner.setSelection(pDest); 

这两个调用调用听众也是!我的结果计算方法加上新结果集的通知在这里调用两次!

对此的一个愚蠢的直接方法是让一个布尔变量禁用无论监听者在里面做什么,在设置选择的项目并在之后重新设置之前进行设置。 好的。但是有没有更好的方法?

我不希望侦听器被代码调用,只能通过用户操作调用! :-(

你怎么办呢? 谢谢!

+0

您可以使用setSelection(pStart,false)设置动画参数。但它不是一直工作。 – sunlover3 2017-08-15 13:04:34

回答

4

听众我有一个更简单的,我认为,更好的解决方案。由于即使在初始化之后,我也必须刷新纺纱机,这是一种更通用的方法。 请参阅接受的答案:

Undesired onItemSelected calls

+0

非常感谢,听起来像一个伟大的方法!当我得到时间时,我将不得不改变我的代码... – Zordid 2014-03-15 09:05:31

+0

有趣的是,你也回答了你自己的问题 - 就像我之前在我的问题中所做的那样。:) – Zordid 2014-03-15 09:06:28

+1

:D是的。更有趣的是,我看到你的答案后,理解回调的工作:) – 2014-03-15 19:46:30

1

每个微调添加OnItemSelectedListener后,你已经设置在onResume以往任何价值。

+2

问题是,正在运行的活动可能会得到一个新的意图,应该将spinners设置为一个新的值 - 因此活动加上它的所有监听器肯定是设置的! 另外:我试图使用'setOnItemSelectedListener(null)'在设置值和稍后恢复监听器之前停用监听器:没有**任何**效果!侦听器被异步调用! :-( – Zordid 2010-02-20 08:22:19

11

好吧,我得到它的工作方式我想现在

了解这里的事情(我没有当我在写这个问题...)是一切的Android在一个线程中运行。 - 在UI线程

含义:即使你在这里和那里设置微调的价值观:他们只更新(视觉)他们的听众只能称为您目前正处于(如onCreateonResume或其他)完成的所有方法。

这允许以下:

  • 保持字段变量选择的位置。 (如currentPos1,currentPos2
  • 听众onItemSelectedListener()调用方法如refreshMyResult()或其他。
  • 以编程方式设置职位时,请设置纺织人员在此之后手动调用您自己的刷新方法。

refreshMyResult()方法是这样的:

int newPos1 = mySpinner1.getSelectedItemPosition(); 
int newPos2 = mySpinner2.getSelectedItemPosition(); 
// only do something if update is not done yet 
if (newPos1 != currentPos1 || newPos2 != currentPos2) { 
    currentPos1 = newPos1; 
    currentPos2 = newPos2; 

    // do whatever has to be done to update things! 

} 

因为听众将在后面叫 - 到那时,在currentPos记住的位置已经被更新 - 什么都不会发生,任何事情没有不必要的更新否则会发生。 当用户在其中一个spinners中选择一个新值时,那么更新将相应地执行!

就是这样! :-)

Ahh - 还有一件事:我的问题的答案是:No. 监听器不能被禁用(很容易),只要值被改变就会被调用。

+2

我有一个类似的问题,使用onCheckChanged,我解决它的方式是通过验证代码被用户输入调用,使用buttonView的isPressed方法。所以尊重,我认为你的方法可能是不明智的,除非我误解了这个问题,请考虑验证它是由用户调用的,而不是onPause()和onResume()方法 – 2011-01-27 18:10:12

+0

我喜欢Zordid的方法,因为无论输入来自哪里(用户输入或之前保存),除非值改变,否则在我的应用程序中做的正确的事情是什么都没有。 – larham1 2011-07-14 02:08:30

+1

@Zach:isPressed()在onItemSelectedListener()中总是为false。根据doc,isPressed()指示视图是否为CURRENTLY处于按下状态。 OnItemSelectedListener注册了一个回调函数,当这个AdapterView中的某个项目被选中时,我在onItemSelectedListener()中放入了一个调试消息,并且发现isPressed()总是精力充沛。在代码中找到isSelected()可能是正确的使用方法。但是不,这个方法在onLitemSelectedListener里面总是失败。所以Zordid的方法只是解决方案,它在我的代码中按预期工作。 – 2012-10-09 06:29:01

2

这是非常容易的,你可以拨打Spinner.setSelection(int position, boolean animate)方法false所以听众不会对变化作出反应。

+0

Works for fin(Api 16) – Cocorico 2014-06-27 15:58:48

+3

animate参数决定微调器动画(是否应直接选择(false)或不选择(true))。它与onItemSelected调用无关。 – 2014-09-22 20:34:15

+1

这不是正确的答案。这不适用于我 - Android 4.4.4。 – 2014-10-21 09:05:05

2

Spinner.setSelection(INT位置,布尔动画)不会触发4.3

+0

这不是我的问题的答案,对不起。 – Zordid 2013-09-18 09:01:50

1

当Spinner.setSelection(位置)时,它总是激活setOnItemSelectedListener()

为了避免烧了两次代码我使用此解决方案:

private mIsSpinnerFirstCall=true; 

... 
Spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 
     //If a new value is selected (avoid activating on setSelection()) 
     if(!mIsSpinnerFirstCall) { 
      // Your code goes gere 
     } 
     mIsSpinnerFirstCall = false; 
    } 

    public void onNothingSelected(AdapterView<?> arg0) { 
    } 
}); 

当您确定我们使用了Spinner.setSelection(position)时,此解决方案有效。此外,使用Spinner.setSelection(位置)

40

一个清洁的解决方案,在我看来,方案和用户发起的更改来区分之前每次设置mIsSpinnerFirstCall = true时,重要的是以下几点:

创建您对微调既是OnTouchListener和OnItemSelectedListener听众

public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener { 

    boolean userSelect = false; 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     userSelect = true; 
     return false; 
    } 

    @Override 
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 
     if (userSelect) { 
      // Your selection handling code here 
      userSelect = false; 
     } 
    } 

} 

的侦听器添加到微调注册两个事件类型

SpinnerInteractionListener listener = new SpinnerInteractionListener(); 
mSpinnerView.setOnTouchListener(listener); 
mSpinnerView.setOnItemSelectedListener(listener); 

这样,由于初始化或重新初始化而对您的处理程序方法的意外调用将被忽略。

+4

绝对是我见过的最好的解决方案。有时候我希望微调者已经被弃用了! – jophde 2015-02-16 20:03:04

+1

如果使用SpinnerInteractionListener抽象类并创建抽象方法onSelected(AdapterView parent,View view,int pos,long id,boolean userSelected),那么您可以捕获所有事件(用户,init等)并以不同的方式对它们做出反应。这就是我需要的。完美的解决方案,谢谢。 – Alexandr 2015-08-28 11:12:07

+0

我已经尝试了所有可能解决与Spinner相关的问题,并且这是最终做到的。我相信凡是实施过微调的人都应该这样做。 API基本上被打破了,这是缺少的功能。非常感谢你! – 2016-11-12 19:01:59

2

我创建了一个库,帮助所有,没有必要要求项目的onClick行动微调 例如:

spinner.setSelection(withAction,position); 

,其中为action是一个布尔标志,是用于呼叫或没有项目的动作

链接在Github上: https://github.com/scijoker/spinner2

+0

很好的解决方案,则失败。工作正常.... – darwin 2017-08-29 12:45:46

0

首先停止微调监听通话

添加布尔值
Boolean check = false; 

然后添加上触摸监听器,并在项目点击以下代码

holder.filters.setOnTouchListener(new View.OnTouchListener() { 
       @Override 
       public boolean onTouch(View v, MotionEvent event) { 

        check = true; 
        return false; 
       } 
      }); 

      holder.filters.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() 
      { 

       @Override 
       public void onItemSelected(AdapterView<?> parent, View arg1, int position, long id) 
       { 
        flag = filterids.get(position); 

        if(check) 
        { 
         check = false; 
         new Applyfilters().execute(flag,"3"); 
        }else{ 

        } 

       } 

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

听众喜欢它的简单工作好停止服务器调用多次。

相关问题