如何在Android中进行平滑的图像旋转?
我正在使用RotateAnimation
来旋转我在Android中用作自定义循环微调器的图像。 这是我放在res/anim/
rotate_indefinitely.xml
文件:
<?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" />
当我使用AndroidUtils.loadAnimation()
其应用于ImageView
,效果非常好!
spinner.startAnimation( AnimationUtils.loadAnimation(activity, R.anim.rotate_indefinitely) );
一个问题是,图像旋转似乎在每个周期的顶部暂停。
换句话说,图像旋转360度,短暂暂停,然后再旋转360度,等等。
我怀疑问题是animation是使用像android:iterpolator="@android:anim/accelerate_interpolator"
( AccelerateInterpolator
)的默认插补器,但我不知道如何告诉它不插入animation。
我怎样才能closures插值(如果这确实是问题),使我的animation循环顺利?
你对AccelerateInterpolator是正确的; 您应该使用LinearInterpolator。
您可以使用android:interpolator="@android:anim/linear_interpolator"
从animationXML文件中使用内置的android.R.anim.linear_interpolator
。
或者您可以在您的项目中创build自己的XML插值文件,例如将其命名为res/anim/linear_interpolator.xml
:
<?xml version="1.0" encoding="utf-8"?> <linearInterpolator xmlns:android="http://schemas.android.com/apk/res/android" />
并添加到您的animationXML:
android:interpolator="@anim/linear_interpolator"
特别提示:如果您的旋转animation是在一个集合内,设置插补器似乎不起作用。 使顶部元素旋转修复它。 (这会节省你的时间。)
我也有这个问题,并试图设置线性插值器在XML中没有成功。 我的解决scheme是在代码中创buildanimation作为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);
这工作正常
<?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" />
尝试使用toDegrees="359"
因为360º和0º是相同的
也许,这样的事情会有所帮助:
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像:
imageView.animate().rotationBy(10000)...
我有完全相同的问题! 修剪 – 元素包裹 – 元素解决问题! 感谢Shalafi! :d
所以你的Rotation_ccw.xml应该像这样:
<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" />
问候
克里斯托弗
正如hanry上面提到的那样,放置衬里的定位器是可以的。 但是如果旋转是在一个集合内,你必须把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,则上面的代码会产生毛刺。
无论我尝试了什么,我都无法使用代码(和setRotation)来顺利旋转animation。 我最终做的是把度数的变化做得很小,以至于小的停顿是不明显的。 如果你不需要做太多的旋转,执行这个循环的时间可以忽略不计。 效果是一个平稳的旋转:
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); }
ObjectAnimatior.ofFloat(view,"rotation",0,360).start();
尝试这个。
是不是有可能因为你从0到360而花费的时间比0/360多一点? 也许设置为359或358。
如果您正在使用像我这样的animation,则应该在set标签内添加插值:
<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>
那为我工作。
在Android中,如果要为对象设置animation并将对象从位置1移动到位置2,则animationAPI会指出中间位置(补间),然后使用计时器在适当的时间将合适的移动操作排队到主线程上。 这工作正常,除了主线程通常用于许多其他的东西 – 绘画,打开文件,响应用户input等排队计时器往往可以延迟。 编写良好的程序将总是尽可能在后台(非主)线程中执行尽可能多的操作,但是不能总是避免使用主线程。 需要您在UI对象上操作的操作总是必须在主线程上完成。 而且,许多API将操作重新引导回主线程,作为线程安全的一种forms。
所有视图都在同一个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)); } }
尝试使用超过360,以避免重新启动。
我使用了360的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%" />