2014-02-13 35 views
11

我有36個spinners,我已經初始化了一些值。我已經使用onItemSelectedListener。像往常一樣,用戶可以與這些spinners進行交互,觸發onItemSeected函數。不希望的onItemSelected調用

一個問題是初始化過程中調用時,但我在這裏找到解決方案,並避免使用全局變量「計數」,並檢查是否計數> 36的內部onItemSelected執行代碼之前。

我的問題是這樣的: 用戶可以選擇點擊一個叫做「Previous」的按鈕,在這個按鈕上我必須重置一些微調值。

我試着在重置spinners之前將count的值改爲0,然後在重置後將它重新更改爲37,但是我明白了onItemSelected僅在每個其他函數執行完畢後纔會調用,所以它稱爲AFTER計數會重新變回37,即使微調器值在用戶選擇時立即設置。

我需要反覆刷新一些spinners而不會觸發onItemSelected函數。任何人都可以幫我找到解決方案嗎?謝謝。

+0

檢查此問題:http://stackoverflow.com/questions/2562248/android-how-to-keep-onitemselected-from-firing-off-on-a-newly-instantiated-spin並嘗試遵循布拉德的建議使用'setSelection()'。 –

+3

我已經嘗試使用setSelection()和false。 onItemSelected內部的代碼仍然執行。 –

+0

@Darth Vedar您可以使用方法setEnabled(true/false)按照您的要求禁用和啓用微調器; – poojagupta

回答

54

我發現一個簡單的,我認爲,優雅的解決方案。 使用標籤。 我先創建一個名爲「標籤」,把下面的代碼一個新的XML文件:

<resources xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item name="pos" type="id" /> 
</resources> 

每當我自己用的spin.setSelection(pos),我也做spin.setTag(R.id.pos, pos),所以我設置的當前位置作爲標記。

然後,在onItemSelected,我執行代碼僅if(spin.getTag(R.id.pos) != position),其中位置是通過函數提供的位置可變。 這樣,我的代碼只有在用戶正在進行選擇時纔會執行。 由於用戶已經做出選擇,標籤還沒有更新,所以處理完成後,我將標籤更新爲spin.setTag(R.id.pos, position)

注意:要使用整個同一個適配器是很重要的,還是「位置」變量可能指向不同的元素。

編輯:作爲kaciula指出的那樣,如果你不使用多個標籤,則可以使用簡單的版本,那就是spin.setTag(pos)spin.getTag()而不需要一個XML文件。

+1

好的解決方案!工作正常。我之前嘗試了很多東西。謝謝! – Rafael

+0

沒問題!很高興它爲你工作:)請一個問題和答案。它可能會幫助其他人:) –

+8

如果您不需要將幾個標籤附加到微調器,您還可以使用setTag(pos)的簡化版本。這樣你就不需要爲密鑰創建xml文件。 –

9

當Spinner.setSelection(位置)時,它總是激活setOnItemSelectedListener()

爲了避免燒了兩次代碼我使用此解決方案:

 private Boolean 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) { 
     } 
    }); 
+0

tks - 保持簡單! – Guihgo

2

我解決的辦法,這是通過保存首先OnItemSelectedListener。然後將Spinner的OnItemSelectedListener設置爲空值。通過代碼在微調器中設置項目後,再次恢復OnItemSelectedListener。這對我有效。

見下面的代碼:

 // disable the onItemClickListener before changing the selection by code. Set it back again afterwards 
     AdapterView.OnItemSelectedListener onItemSelectedListener = historyPeriodSpinner.getOnItemSelectedListener(); 
     historyPeriodSpinner.setOnItemSelectedListener(null); 
     historyPeriodSpinner.setSelection(0); 
     historyPeriodSpinner.setOnItemSelectedListener(onItemSelectedListener); 
+1

這是一個好主意,但在調用setSelection()之後設置(非空)偵聽器仍然會導致偵聽器被調用。 – stevehs17

0

這裏是我解決這個問題。我擴展AppCompatSpinner並添加方法pgmSetSelection(int pos),該方法允許編程選擇設置而不觸發選擇回調。我已經使用RxJava對此進行了編碼,以便通過Observable傳遞選擇事件。

package com.controlj.view; 

import android.content.Context; 
import android.util.AttributeSet; 
import android.view.View; 
import android.widget.AdapterView; 

import io.reactivex.Observable; 

/** 
* Created by clyde on 22/11/17. 
*/ 

public class FilteredSpinner extends android.support.v7.widget.AppCompatSpinner { 
    private int lastSelection = INVALID_POSITION; 


    public void pgmSetSelection(int i) { 
     lastSelection = i; 
     setSelection(i); 
    } 

    /** 
    * Observe item selections within this spinner. Events will not be delivered if they were triggered 
    * by a call to setSelection(). Selection of nothing will return an event equal to INVALID_POSITION 
    * 
    * @return an Observable delivering selection events 
    */ 
    public Observable<Integer> observeSelections() { 
     return Observable.create(emitter -> { 
      setOnItemSelectedListener(new OnItemSelectedListener() { 
       @Override 
       public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
        if(i != lastSelection) { 
         lastSelection = i; 
         emitter.onNext(i); 
        } 
       } 

       @Override 
       public void onNothingSelected(AdapterView<?> adapterView) { 
        onItemSelected(adapterView, null, INVALID_POSITION, 0); 
       } 
      }); 
     }); 
    } 

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

    public FilteredSpinner(Context context, int mode) { 
     super(context, mode); 
    } 

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

    public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
    } 

    public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) { 
     super(context, attrs, defStyleAttr, mode); 
    } 
} 

Fragment例如它的用法,所謂在onCreateView()的一個例子:

mySpinner = view.findViewById(R.id.history); 
    mySpinner.observeSelections() 
     .subscribe(this::setSelection); 

其中setSelection()是看起來像這樣的包圍視圖的方法,並且其都從用戶調用選擇事件通過Observable以及其他地方編程,因此處理選擇的邏輯對於兩種選擇方法都是通用的。

private void setSelection(int position) { 
    if(adapter.isEmpty()) 
     position = INVALID_POSITION; 
    else if(position >= adapter.getCount()) 
     position = adapter.getCount() - 1; 
    MyData result = null; 
    mySpinner.pgmSetSelection(position); 
    if(position != INVALID_POSITION) { 
     result = adapter.getItem(position); 
    } 
    display(result); // show the selected item somewhere 
} 
1

我不知道,如果這個解決方案是在這裏所選擇的一個爲做到萬無一失,但它很適合我,似乎更簡單:

boolean executeOnItemSelected = false; 
spinner.setSelection(pos) 

然後在OnItemSelectedListener

public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 
    if(executeOnItemSelected){ 
     //Perform desired action 
    } else { 
     executeOnItemSelected = true; 
    } 
}