35

只是想知道您如何处理以下问题:根据两个微调器的选定项目计算结果。为了处理 UI 事务,即用户在其中一个微调器中选择一个新项目,我setOnItemSelectedListener在我onCreate()的活动方法中为微调器安装了一个侦听器。

现在:当然,这行得通。侦听器的工作是触发新的计算结果。

问题:因为我拦截onPause() onResume()以保存/恢复最后一个状态,所以我有一个方法可以像这里一样以编程方式设置这两个微调器的选定项目:

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

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

一个愚蠢的直接方法是使用一个布尔变量来禁用侦听器在内部所做的任何事情,在设置所选项目之前设置它并在之后重置它。好的。但是有没有更好的方法??

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

你怎么做呢?谢谢!

4

12 回答 12

51

在我看来,区分程序化和用户发起的更改的更简洁的解决方案如下:

为微调器创建您的侦听器作为 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);

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

于 2015-02-11T23:52:34.963 回答
11

好的,我让它按照我现在想要的方式工作。

这里要理解的事情(当我写这个问题时我没有......)是Android中的所有东西都在一个线程中运行 - UI线程。

含义:即使您在这里和那里设置 Spinner 的值:它们仅会更新(视觉上),并且仅在您当前使用的所有方法(例如,或其他)完成后才调用它们的侦听器。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 中记住的位置已经更新 - 什么都不会发生,也不会发生任何不必要的更新。当用户在其中一个微调器中选择一个新值时,那么 - 将相应地执行更新!

就是这样!:-)

啊-还有一件事:我的问题的答案是:不。无法(轻松地)禁用侦听器,并且每当更改值时都会调用侦听器。

于 2010-02-24T14:00:51.693 回答
6

我有一个更简单,而且我认为更好的解决方案。由于即使在初始化之后我也必须刷新微调器,所以这是一种更通用的方法。请参考接受的答案:

不需要的 onItemSelected 调用

于 2014-02-13T10:23:38.847 回答
3

首先添加布尔值以停止微调器侦听器调用

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

它很简单,可以多次停止服务器调用。

于 2017-08-30T04:37:20.800 回答
2

您可以很容易地调用该Spinner.setSelection(int position, boolean animate)方法,false这样听众就不会对更改做出反应。

于 2013-07-12T09:08:50.280 回答
2

Spinner.setSelection(int position, boolean animate) 确实会在 4.3 上触发监听器

于 2013-09-05T16:27:52.367 回答
2

我创建了一个对所有人都有帮助的库,无需在 Spinner 中调用 item onClick 操作 例如:

spinner.setSelection(withAction,position);

其中 withAction 是一个布尔标志,用于调用或不调用项目操作

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

于 2015-10-11T19:55:23.593 回答
2

我的解决方案非常简单。首先初始化一个全局布尔变量。

boolean shouldWork = true;

然后在您的 onCreate() 方法中使用以下代码。

Spinner spinner = findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView adapter, View v, int i, long lng) {
        if (shouldWork) {
               // Do your actions here
        }
        else
            shouldWork = true;
    }
    public void onNothingSelected(AdapterView<?> parentView)  {

    }
});

现在您可以在任何地方使用 setSelection 方法,而无需通过以下代码调用 onItemSelected() 方法。

shouldWork = false;
spinner.setSelection(0);
于 2018-09-21T16:59:49.797 回答
1

在中设置任何先前的值OnItemSelectedListener,为每个微调器添加。onResume

于 2010-02-19T16:39:59.183 回答
1

当使用 Spinner.setSelection(position) 时,它总是激活 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(position) 之前设置 mIsSpinnerFirstCall=true 也很重要

于 2014-10-22T11:03:12.437 回答
1

就我而言,由于我以编程方式触发微调器,因此我只需在spinner.performClick()之后添加spinnerSelected标志,如下所示。

private var spinnerSelected = false

someView.setOnClickListener {
    spinner.performClick()
    spinnerSelected = true
}

spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
    override fun onNothingSelected(parent: AdapterView<*>?) {
        // do nothing
    }

    override fun onItemSelected(
        parent: AdapterView<*>?,
        view: View?,
        position: Int,
        id: Long
    ) {
        if (spinnerSelected) {
            //... do something

            spinnerSelected = false
        }
      }
    }
于 2020-01-30T03:14:19.580 回答
0
    This following method will help you to stop invoking automatically the selection listener


    yourspinnerobj.post(new Runnable() {
                @Override
                public void run() {
                    yourspinnerobj.setOnItemSelectedListener(yourspinnerlistener);
                }
            });
于 2018-06-07T08:44:35.913 回答