2010-04-14 145 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