2010-02-19 34 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 
       } 
      }); 

聽衆喜歡它的簡單工作好停止服務器調用多次。

相關問題