2012-11-21 45 views
9

我爲Android創建了一個應用程序,其中有一個NumberPicker。而且我需要改變這個NumberPicker的值,但是用一個平滑的動畫,比如當你觸摸它並改變它的值時。如何使用動畫更改NumberPicker的值?

例如,假設當前值爲1,它將爲5,我希望NumberPicker從1旋轉到2,然後旋轉到3,依此類推。但我希望它不僅能立即改變價值!

如果我使用下面的代碼:

numberPicker.setValue(5); 

它的價值會立即更改爲5,但我想它從1捲起至5就像當你手動觸摸它,使其旋轉。

回答

15

我通過refelction

 /** 
     * using reflection to change the value because 
     * changeValueByOne is a private function and setValue 
     * doesn't call the onValueChange listener. 
     * 
     * @param higherPicker 
     *   the higher picker 
     * @param increment 
     *   the increment 
     */ 
     private void changeValueByOne(final NumberPicker higherPicker, final boolean increment) { 

      Method method; 
      try { 
       // refelction call for 
       // higherPicker.changeValueByOne(true); 
       method = higherPicker.getClass().getDeclaredMethod("changeValueByOne", boolean.class); 
       method.setAccessible(true); 
       method.invoke(higherPicker, increment); 

      } catch (final NoSuchMethodException e) { 
       e.printStackTrace(); 
      } catch (final IllegalArgumentException e) { 
       e.printStackTrace(); 
      } catch (final IllegalAccessException e) { 
       e.printStackTrace(); 
      } catch (final InvocationTargetException e) { 
       e.printStackTrace(); 
      } 
     } 

可以完美解決了這個問題。我不知道爲什麼這種方法是私人的

+0

用你的技術來解決[這個問題](http://stackoverflow.com/q/17708325/473232)。謝謝。 – dgel

+0

對不起,以恢復舊的線程,但會有一個簡單的方法來獲得這個增加NumberPicker遞減,而不是越來越多? 編輯:明白!只需要將參數改爲false而不是true。 – intA

+0

我很自豪能夠復活這個舊線程。兩年後,這對我有用!我開始想知道爲什麼幾個組件中的很多功能都是私有的。這幾乎令人沮喪。 –

3

我不認爲這是本機支持的。我想到了一個手動執行的'混亂'的方法:

您可以使用NumberPicker的scrollBy(int x,int y)函數迭代地調用動畫效果。

有些事情要考慮:

  • scrollBy(X,Y)的作品與像素。由於Android具有所有不同的屏幕密度,因此您應該首先猜測(我會通過反覆試驗來實現)與滾動到連續值相對應的「dp」距離,然後將其轉換爲像素以便用它。
  • scrollBy(X,Y)的第一個參數應以0值,如果它不是很明顯

我沒有在Android的動畫製作自己,但有一個很好的API,因爲蜂窩可能很容易做到這一點。

對不起,但這是我能想到的最簡單!

編輯:爲了從 'DP' 轉換爲像素:

private float pxFromDp(float dp) 
{ 
    return dp * this.getContext().getResources().getDisplayMetrics().density; 
} 

你必須做的是測試調用scrollBy(0,pxFromDp(DP))與不同的 'DP' 值,直到你獲得將NumberPicker向上移動一個數字的確切形式。一旦你獲得了這個值,你就可以創建你的動畫方法,當向上移動X個數字時將滾動X倍這個Dp距離。

請再次問,如果你不完全理解它:)

+0

哦,謝謝你的很聰明的答案;-) 請您解釋一下您的第一點你提到?關於'dp'和'像素'。 我會試試看,並讓你知道(當然通過將答案標記爲接受的答案:D) 再次感謝你! – Mehran

+0

我將其添加到說明:) – alfongj

+0

不適合我。只是使用* scrollBy(x,y)*不會產生與手動滾動相同的效果。例如。當前選定的號碼根本不滾動,它只停留在中心,然後換成新的號碼。 *上*,*下*箭頭在滾動時不會消失。 –

1

裏面有NumberPicker,這是

changeCurrentByOne(boolean increment) 

私有方法,你可以把它公開,並使用它。當按下UPDOWN NumberPicker的箭頭時,您可以看到此方法正在運行。可能它不是你要找的東西,因爲這種方法不能很好地控制動畫,但它確實比setValue更好。沒有任何動畫setValue對用戶來說看起來很糟糕。

2

謝謝@passsy。啓發他的回答:該解決方案支持多個遞增/遞減步驟。此外,可以用啓動延遲執行多個編號(無需額外編碼)

class IncreaseValue { 
    private int counter = 0; 
    private final NumberPicker picker; 
    private final int incrementValue; 
    private final boolean increment; 

    private final Handler handler = new Handler(); 
    private final Runnable fire = new Runnable() { @Override public void run() { fire(); } }; 

    /*public*/ IncreaseValue(final NumberPicker picker, final int incrementValue) { 
     this.picker = picker; 
     if (incrementValue > 0) { 
      increment = true; 
      this.incrementValue = incrementValue; 
     } else { 
      increment = false; 
      this.incrementValue = -incrementValue; 
     } 
    } 

    /*public*/ void run(final int startDelay) { 
     handler.postDelayed(fire, startDelay); // This will execute the runnable passed to it (fire) 
     // after [startDelay in milliseconds], ASYNCHRONOUSLY. 
    } 

    private void fire() { 
     ++counter; 
     if (counter > incrementValue) return; 

     try { 
      // refelction call for 
      // picker.changeValueByOne(true); 
      final Method method = picker.getClass().getDeclaredMethod("changeValueByOne", boolean.class); 
      method.setAccessible(true); 
      method.invoke(picker, increment); 

     } catch (final NoSuchMethodException | InvocationTargetException | 
       IllegalAccessException | IllegalArgumentException e) { 
      Log.d(TAG, "...", e); 
     } 

     handler.postDelayed(fire, 120); // This will execute the runnable passed to it (fire) 
     // after 120 milliseconds, ASYNCHRONOUSLY. Customize this value if necessary. 
    } 
} 

用法:

// Suppose picker1 as a NumberPicker 
IncreaseValue increasePicker1 = new IncreaseValue(picker1, 10); // So picker1 will be increased 10 steps. 
increasePicker1.run(0); // Increase immediately. If you want to run it from onCreate(), onStart() or ... of your activity, you will probably need to pass a positive value to it (e.g. 100 milliseconds). 
相關問題