2011-10-01 18 views
8

私は最初からカスタムビューを作成しました。 Viewを拡張し、onDraw()を上書きします。 ビューがアニメーション化されると、私はオフセットを使ってカスタムアニメーションを生成します。例えば、 。どのようにしてAndroidでアニメーションビューを描画できますか?

while(!isOnTop){ 
mOffset++; 

//draw the component a a it higher using the offset 

if(position == 0) 
isOnTop==true; 
invalidate(); 

} 

私のフレームは自分自身を無効にするからです。問題は、同じ画面でリストビューをスクロールするだけで、このビューの無効化が可能になることです。

この「共有無効化()」は、私のアニメーションの遅れを引き起こします。その遅れから脱出する方法はありますか?

共有環境でアニメーションを実行することについての他の提案はありますか? オフセットを計算する別々のスレッドを使ってアニメーションを作成するには、アニメーションを表示するために強制的なinvalidation()呼び出しが必要です(私が間違っている場合は修正してください)。

アニメーションを実行する唯一の方法は、例えば10段階の無効化要求で大きなステップを使用することですか?それは遅れを緩和しますが、私はそれについて別のアプローチを使うことができると思います。

答えて

4

この質問には何らかの関心があるので、私は返信します。

これを行う最善の方法は、別のキャンバススレッドを持つことです。 「別の」キャンバスはSurfaceViewでのみ達成できます。 LunarLandingは、その使用の優れた例です。各フレームは、描画時間ではなくCPU時間のみを共有するメインビューとは別に計算されます。したがって、上部の通常のビューと下部のアニメーションのビューの組み合わせであっても、より高速です。

しかし、共有環境にいる場合は、間隔を設定する必要があります。この間隔は、FPSキャップに使用されます。 FPSの上限を設定しないと、CPUが野生的に実行され、単独の場合はSurfaceViewに良いアニメーションが表示されます。それを60fpsまたはそれ以下でキャッピングすると、CPUオーバーロードなしですべてのビューを効率的に描画することができます。

APIデモからLunar Landingの描画スレッドを見て、FPS上限を設定します。

private long timeNow; 
    private long timeDelta; 
    private long timePrevFrame; 

    private void capFps(int fps) { 
      timeNow = System.currentTimeMillis(); 
      timeDelta = timeNow - timePrevFrame;   

      try { 

// psのあなたは常に計算を毎回

Thread.sleep((1000/fps) - timeDelta); 
      } catch (InterruptedException e) { 

      } 

      timePrevFrame = System.currentTimeMillis(); 
    } 

を避けるために、16の代わりに、60FPS 1000/FPSを設定することができ、その後、描画スレッドは次のようなものになります。

@Override 
    public void run() { 
     Canvas c; 

     while (run) { 
      c = null; 
      sleepFps(60, false); 
      try { 
       synchronized (surfaceHolder) { 
        c = surfaceHolder.lockCanvas(null); 
        widgetView.doDraw(c); 
       } 
      } finally { 
       if (c != null) { 
        surfaceHolder.unlockCanvasAndPost(c); 
       } 
      } 

     } 
    } 
+0

申し訳ありませんが、これは*多くの場合、必要以上*より複雑な方法であり、SurfaceViewは、多くの場合、最適なソリューションを、それをない作る多くの妥協を持っています。 – hackbod

+0

はい、それだけではありませんが、一緒に複数のアニメーションのビューを持っている最高のものです。質問は「ベスト」なのですが、答えは – weakwire

+0

ありがとうございます。これは実際に私がj2meから慣れ親しんでいる方法です。計算が気に入らなければ、いつでもそれをスキップして一定時間眠ることができます。 –

23

"何がベスト"はもちろん、何をしようとしているかに大きく依存します。あなたはあなたが達成しようとしていることを言っていないので、私たちはあなたのために最善であるかもしれないものだけを推測することができます。あなたは、階層内のビューの動きをアニメーション化する場合はhttp://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

  • 、ビューを使用する:あなたは、ビットマップフレームをアニメーションAnimationDrawableを使用したい場合は

    • :ここ

      は、いくつかの簡単なものですアニメーションフレームワーク:http://developer.android.com/guide/topics/graphics/view-animation.html

    • 新しいより一般的なアニメーションフレームワークは、しばしばより使いやすい多くの素材を使用できます:http://developer.android.com/guide/topics/graphics/animation.html。これはAndroid 3.0以降ではネイ​​ティブで利用できますが、サポートv7ライブラリでAndroid APIレベル7でも使用できます。

    • ビュー階層の統合部分であるカスタムウィジェットを作成し、独自のアニメーション図面を手動で作成する場合は、ハンドラを使用して更新をタイムラグできます(通常は、それぞれ60fpsまたは20msが必要です)。 invalidate())し、onDraw()メソッドでは、アニメーションの開始時からの差分としてSystemClock.uptimeMillis()に基づいてビューの状態を描画します。

    ここハンドラを使用して、単純な繰り返し無効です:

    long mAnimStartTime; 
    
    Handler mHandler = new Handler(); 
    Runnable mTick = new Runnable() { 
        public void run() { 
         invalidate(); 
         mHandler.postDelayed(this, 20); // 20ms == 60fps 
        } 
    } 
    
    void startAnimation() { 
        mAnimStartTime = SystemClock.uptimeMillis(); 
        mHandler.removeCallbacks(mTick); 
        mHandler.post(mTick); 
    } 
    
    void stopAnimation() { 
        mHandler.removeCallbacks(mTick); 
    } 
    
  • +1

    invalidate()は即時ではありません。無効にするのに必要なビューがたくさんあるので、20ms以上かかることがあります。ビューは、すべてが終了するまで待つ必要があります(少なくとも3.0より前)。 postDelayedはさらに遅れを導入します。そのようにfpsを制限するのは良くありません。私が間違っている場合は、私を訂正してください。 – weakwire

    +2

    実際はありません。 invalidate()が20ms以上かかる場合、ビュー階層をどのように構造化したかには深刻な問題があります。標準プラットフォームのウィンドウ内のアニメーションの大部分は、invalidate()で定期的なビューを使用し、60fpsを達成できます。複数の大きな不透明なビットマップを互いの上に置いたり、描画を遅くするようにスケーリングするなど、ビューの階層構造では行かないようにするだけですが、とにかくそれをやりたくはありません。 – hackbod

    +12

    20ms 50fpsではありませんか? –

    関連する問題