2009-10-27 96 views
167

我使用的是RotateAnimation來旋轉我在Android中用作自定義循環微調器的圖像。這是我的rotate_indefinitely.xml文件,我放在res/anim/如何在Android中進行平滑的圖像旋轉?

<?xml version="1.0" encoding="UTF-8"?> 
<rotate 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromDegrees="0" 
    android:toDegrees="360" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:repeatCount="infinite" 
    android:duration="1200" />  

當我將此我ImageView使用AndroidUtils.loadAnimation(),它的偉大工程!

spinner.startAnimation( 
    AnimationUtils.loadAnimation(activity, R.anim.rotate_indefinitely)); 

一個問題是,圖像旋轉似乎在每個週期的頂部暫停。

換句話說,圖像旋轉360度,短暫暫停,然後再次旋轉360度,等等

我懷疑是問題是,動畫使用像android:iterpolator="@android:anim/accelerate_interpolator"默認內插器(AccelerateInterpolator),但我不知道如何告訴它不要插入動畫。

如何關閉插值(如果確實是問題),以使我的動畫循環順利進行?

回答

178

你說得對AccelerateInterpolator;您應該使用LinearInterpolator。

您可以使用android:interpolator="@android:anim/linear_interpolator"的動畫XML文件中的內置android.R.anim.linear_interpolator

或者您可以在您的項目中創建自己的XML插值文件,例如它命名爲res/anim/linear_interpolator.xml

<?xml version="1.0" encoding="utf-8"?> 
<linearInterpolator xmlns:android="http://schemas.android.com/apk/res/android" /> 

並添加到您的動畫XML:

android:interpolator="@anim/linear_interpolator" 

特別提示:如果旋轉的動畫是一家集內,設置內插器似乎不工作。使頂部元素旋轉修復它。 (這會節省您的時間。)

+1

這是因爲內插器拼錯了(不是「n」)。你不需要自己製作 – Kingpin 2011-02-18 20:42:53

+22

我已經試過了每一個可用的插補器,包括線性的,在每個週期的開始我仍然會得到這個小小的「連結」。 – 2011-08-23 19:01:40

+11

如果您的旋轉動畫在一組內,設置插補器似乎不起作用。使旋轉頂部元素修復它 – shalafi 2012-05-16 11:52:58

1

是否有可能因爲您從0到360而在0/360處花費的時間比您期望的要多一點?也許設置爲359或358.

+1

偉大理論。我非常確定這不是因爲加速/減速非常順利,而且故意尋找。以防萬一,儘管我嘗試將學位降低到358,並且行爲沒有明顯的變化。 – emmby 2009-10-28 00:33:07

26

嘗試使用toDegrees="359"因爲360°和0°是相同的。

3

無論我嘗試了什麼,我都無法使用代碼(和setRotation)正確使用平滑旋轉動畫。我最終做的事情是把度數的變化做得很小,以至於小的停頓是不明顯的。如果你不需要做太多的旋轉,執行這個循環的時間可以忽略不計。其效果是平滑的旋轉:

 float lastDegree = 0.0f; 
     float increment = 4.0f; 
     long moveDuration = 10; 
     for(int a = 0; a < 150; a++) 
     { 
      rAnim = new RotateAnimation(lastDegree, (increment * (float)a), Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 
      rAnim.setDuration(moveDuration); 
      rAnim.setStartOffset(moveDuration * a); 
      lastDegree = (increment * (float)a); 
      ((AnimationSet) animation).addAnimation(rAnim); 
     } 
28

這工作得很好

<?xml version="1.0" encoding="UTF-8"?> 
<rotate xmlns:android="http://schemas.android.com/apk/res/android" 
    android:duration="1600" 
    android:fromDegrees="0" 
    android:interpolator="@android:anim/linear_interpolator" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:repeatCount="infinite" 
    android:toDegrees="358" /> 

爲了扭轉旋轉:

<?xml version="1.0" encoding="UTF-8"?> 
<rotate xmlns:android="http://schemas.android.com/apk/res/android" 
    android:duration="1600" 
    android:fromDegrees="358" 
    android:interpolator="@android:anim/linear_interpolator" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:repeatCount="infinite" 
    android:toDegrees="0" /> 
+4

對於反向,只需要repeatcount 2並設置android:repeatMode =「reverse」 - 不需要有兩個不同的XML文件。 – 2014-11-16 22:02:28

+0

爲什麼358而不是359或360? – behelit 2017-03-21 04:02:31

+0

在哪裏可以添加此文件到資源?動畫是一個單獨的包嗎? – abggcv 2017-05-09 19:27:06

5

修剪<set> - 元素是包裹<rotate> - 元素解決了這個問題!

感謝Shalafi!

所以,你應該Rotation_ccw.xml loook這樣的:

<?xml version="1.0" encoding="utf-8"?> 

<rotate 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromDegrees="0" 
    android:toDegrees="-360" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:duration="2000" 
    android:fillAfter="false" 
    android:startOffset="0" 
    android:repeatCount="infinite" 
    android:interpolator="@android:anim/linear_interpolator" 
    /> 
3

正如hanry上面已經把內膽iterpolator是罰款提及。但是如果旋轉是在一個集合內,你必須把android:shareInterpolator =「false」使它平滑。

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android" 
**android:shareInterpolator="false"** 
> 
<rotate 
    android:interpolator="@android:anim/linear_interpolator" 
    android:duration="300" 
    android:fillAfter="true" 
    android:repeatCount="10" 
    android:repeatMode="restart" 
    android:fromDegrees="0" 
    android:toDegrees="360" 
    android:pivotX="50%" 
    android:pivotY="50%" /> 
<scale xmlns:android="http://schemas.android.com/apk/res/android" 
    android:interpolator="@android:anim/linear_interpolator" 
    android:duration="3000" 
    android:fillAfter="true" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:fromXScale="1.0" 
    android:fromYScale="1.0" 
    android:toXScale="0" 
    android:toYScale="0" /> 
</set> 

如果Sharedinterpolator不是false,上面的代碼會產生毛刺。

40

我也遇到了這個問題,並試圖在xml中設置線性插補器而沒有成功。爲我工作的解決方案是在代碼中將動畫創建爲RotateAnimation。

RotateAnimation rotate = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 
rotate.setDuration(5000); 
rotate.setInterpolator(new LinearInterpolator()); 

ImageView image= (ImageView) findViewById(R.id.imageView); 

image.startAnimation(rotate); 
0

在Android中,如果要設置動畫的對象,並使其從LOCATION1將對象移動到LOCATION2,動畫API計算出中間位置(漸變),然後排隊到主線程相應的移動操作在適當的時候使用定時器。這工作正常,除了主線程通常用於許多其他的東西 - 繪畫,打開文件,響應用戶輸入等排隊計時器通常可以延遲。編寫良好的程序將總是儘可能在後臺(非主)線程中執行儘可能多的操作,但是不能總是避免使用主線程。需要您在UI對象上操作的操作始終必須在主線程上完成。而且,許多API會將操作作爲線程安全的一種形式回溯到主線程。

所有視圖都繪製在同一個GUI線程上,也用於所有用戶交互。

因此,如果您需要快速更新GUI,或者如果渲染花費太多時間並影響用戶體驗,請使用SurfaceView。旋轉圖像的

例子:

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback { 
    private DrawThread drawThread; 

    public MySurfaceView(Context context) { 
     super(context); 
     getHolder().addCallback(this); 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, 
      int height) { 
    } 

    @Override 
    public void surfaceCreated(SurfaceHolder holder) { 
     drawThread = new DrawThread(getHolder(), getResources()); 
     drawThread.setRunning(true); 
     drawThread.start(); 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
     boolean retry = true; 
     drawThread.setRunning(false); 
     while (retry) { 
      try { 
       drawThread.join(); 
       retry = false; 
      } catch (InterruptedException e) { 
      } 
     } 
    } 
} 


class DrawThread extends Thread{ 
    private boolean runFlag = false; 
    private SurfaceHolder surfaceHolder; 
    private Bitmap picture; 
    private Matrix matrix; 
    private long prevTime; 

    public DrawThread(SurfaceHolder surfaceHolder, Resources resources){ 
     this.surfaceHolder = surfaceHolder; 

     picture = BitmapFactory.decodeResource(resources, R.drawable.icon); 

     matrix = new Matrix(); 
     matrix.postScale(3.0f, 3.0f); 
     matrix.postTranslate(100.0f, 100.0f); 

     prevTime = System.currentTimeMillis(); 
    } 

    public void setRunning(boolean run) { 
     runFlag = run; 
    } 

    @Override 
    public void run() { 
     Canvas canvas; 
     while (runFlag) { 
      long now = System.currentTimeMillis(); 
      long elapsedTime = now - prevTime; 
      if (elapsedTime > 30){ 

       prevTime = now; 
       matrix.preRotate(2.0f, picture.getWidth()/2, picture.getHeight()/2); 
      } 
      canvas = null; 
      try { 
       canvas = surfaceHolder.lockCanvas(null); 
       synchronized (surfaceHolder) { 
        canvas.drawColor(Color.BLACK); 
        canvas.drawBitmap(picture, matrix, null); 
       } 
      } 
      finally { 
       if (canvas != null) { 
        surfaceHolder.unlockCanvasAndPost(canvas); 
       } 
      } 
     } 
    } 
} 

活動:

public class SurfaceViewActivity extends Activity { 
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(new MySurfaceView(this)); 
    } 
} 
1

如果您正在使用一組動畫像我這樣的,你應該添加一組標籤內插:

<set xmlns:android="http://schemas.android.com/apk/res/android" 
android:interpolator="@android:anim/linear_interpolator"> 

<rotate 
    android:duration="5000" 
    android:fromDegrees="0" 
    android:pivotX="50%" 
    android:pivotY="50%" 
    android:repeatCount="infinite" 
    android:startOffset="0" 
    android:toDegrees="360" /> 

<alpha 
    android:duration="200" 
    android:fromAlpha="0.7" 
    android:repeatCount="infinite" 
    android:repeatMode="reverse" 
    android:toAlpha="1.0" /> 

</set> 

那爲我工作。

15

也許,這樣的事情會有所幫助:

Runnable runnable = new Runnable() { 
    @Override 
    public void run() { 
     imageView.animate().rotationBy(360).withEndAction(this).setDuration(3000).setInterpolator(new LinearInterpolator()).start(); 
    } 
}; 

imageView.animate().rotationBy(360).withEndAction(runnable).setDuration(3000).setInterpolator(new LinearInterpolator()).start(); 

順便說一句,你可以通過360多個像旋轉:

​​
+0

工作完美,imageView.clearAnimation()會清理runnable嗎? – XcodeNOOB 2016-09-13 08:00:44

+0

它對於啓動動畫工作正常,但啓動後可以通過imageView.clearAnimation()清理它的不清除,我用於監聽事件 – 2017-03-08 12:38:24

3
ObjectAnimatior.ofFloat(view,"rotation",0,360).start(); 

試試這個。

0

嘗試使用超過360個以避免重新啓動。

我用3600 insted的360,這正常工作對我來說:

<rotate xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromDegrees="0" 
    android:toDegrees="3600" 
    android:interpolator="@android:anim/linear_interpolator" 
    android:repeatCount="infinite" 
    android:duration="8000" 
    android:pivotX="50%" 
    android:pivotY="50%" />