안드로이드에서 이미지를 부드럽게 회전시키는 방법은 무엇입니까?


217

RotateAnimationAndroid에서 커스텀 주기적 스피너로 사용하는 이미지를 회전시키는 데 a 를 사용하고 있습니다. 여기 내 rotate_indefinitely.xml파일이 있습니다 res/anim/.

<?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 ) 하지만 애니메이션을 보간하지 말라고하는 방법을 모르겠습니다.

내 애니메이션을 부드럽게 순환시키기 위해 보간을 끄려면 어떻게해야합니까?

답변:


199

귀하는 AccelerateInterpolator에 대해 맞습니다. 대신 LinearInterpolator를 사용해야합니다.

android.R.anim.linear_interpolator애니메이션 XML 파일 의 내장 기능 을android:interpolator="@android: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

25
나는 선형을 포함하여 사용 가능한 모든 보간기를 시도했지만 모든 사이클의 시작 부분에서 여전히이 작은 "히치"를 얻습니다.
Adam Rabung

11
회전 애니메이션이 세트 안에 있으면 보간 기 설정이 작동하지 않는 것 같습니다. 상단 요소를 회전 시키면 문제가 해결됩니다
shalafi

실제로 모든 애니메이션 사이에 작은 "일시 정지"없이 가속 _ 감속 _ 보간기를 사용하려면 어떻게해야합니까?
agonist_ 2016 년

90

나는 또한이 문제가 있었고 성공하지 않고 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);

9
애니메이션이 마지막 방향으로 유지되도록하려면rotate.setFillAfter(true);
Fonix

4
애니메이션을 rotate.setRepeatCount(Animation.INFINITE);
끝없이

38

이것은 잘 작동합니다

<?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" />

5
반대로, 반복 횟수 2를 설정하고 android : repeatMode = "reverse"를 설정하십시오. 두 개의 다른 XML 파일이 필요하지 않습니다.
RoundSparrow hilltx 2018

3
왜 359 또는 360이 아닌 358입니까?
behelit

이 파일을 리소스에서 어디에 추가합니까? 애니메이션이 별도의 패키지입니까?
abggcv

30

아마도 다음과 같은 것이 도움이 될 것입니다.

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)...

완벽하게 작동하면 imageView.clearAnimation ()이 실행 파일을 정리합니까?
XcodeNOOB

애니메이션 시작에는 문제가 없지만
startViewable

이 런너 블을 독립적으로 멈출 수 없음
바지

@Pants 당신은 어떤 조건에서 EndAction (this)으로 호출 할 수 있습니다. 조건이 거짓이면 withAction (this)이 호출되지 않고 애니메이션이 중지되어야합니다.
Vitaly Zinchenko



8

프로그래밍 방식으로 회전 객체.

// 시계 방향 회전 :

    public void rotate_Clockwise(View view) {
        ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 180f, 0f);
//        rotate.setRepeatCount(10);
        rotate.setDuration(500);
        rotate.start();
    }

// 반 시계 방향 회전 :

 public void rotate_AntiClockwise(View view) {
        ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 0f, 180f);
//        rotate.setRepeatCount(10);
        rotate.setDuration(500);
        rotate.start();
    } 

view 는 ImageView 또는 다른 위젯의 객체입니다.

rotate.setRepeatCount (10); 회전을 반복하는 데 사용합니다.

애니메이션 시간은 500 입니다.


6

<set>줄 바꿈-요소 정리<rotate> - 요소로 해결할 수있는 문제를 문제를!

Shalafi에게 감사합니다!

따라서 Rotation_ccw.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:duration="2000"
    android:fillAfter="false"
    android:startOffset="0"
    android:repeatCount="infinite"
    android:interpolator="@android:anim/linear_interpolator"
    />

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);
        }

"애니메이션"변수 선언은 어디에 있습니까?
Rishabh Saxena

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가 아닌 경우 위 코드는 글리치를 제공합니다.


3

나와 같은 세트 애니메이션을 사용하는 경우 세트 태그 안에 보간을 추가해야합니다.

<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>

그것은 나를 위해 일했다.


3

코 틀린에서 :

 ivBall.setOnClickListener(View.OnClickListener {

            //Animate using XML
            // val rotateAnimation = AnimationUtils.loadAnimation(activity, R.anim.rotate_indefinitely)

            //OR using Code
            val rotateAnimation = RotateAnimation(
                    0f, 359f,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f

            )
            rotateAnimation.duration = 300
            rotateAnimation.repeatCount = 2

            //Either way you can add Listener like this
            rotateAnimation.setAnimationListener(object : Animation.AnimationListener {

                override fun onAnimationStart(animation: Animation?) {
                }

                override fun onAnimationRepeat(animation: Animation?) {
                }

                override fun onAnimationEnd(animation: Animation?) {

                    val rand = Random()
                    val ballHit = rand.nextInt(50) + 1
                    Toast.makeText(context, "ballHit : " + ballHit, Toast.LENGTH_SHORT).show()
                }
            })

            ivBall.startAnimation(rotateAnimation)
        })

1

0에서 360으로 이동하기 때문에 예상보다 0/360에서 조금 더 많은 시간을 할애 할 수 있습니까? 아마도 359 또는 358로 설정됩니다.


1
위대한 이론. 속도 향상 / 감속이 매우 부드럽고 고의적으로 보이기 때문에 그렇지 않다고 확신합니다. 내가 학위를 358로 낮추려고 시도했지만 행동에 눈에 띄는 변화가 없었던 경우를 대비하여.
emmby

1

다시 시작하지 않도록 360 이상을 사용하십시오.

나는 360의 3600 insted를 사용하며 이것은 나에게 잘 작동한다.

<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%" />

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));
    }
}

0
private fun rotateTheView(view: View?, startAngle: Float, endAngle: Float) {
    val rotate = ObjectAnimator.ofFloat(view, "rotation", startAngle, endAngle)
    //rotate.setRepeatCount(10);
    rotate.duration = 400
    rotate.start()
}

1
이 코드는 질문에 대한 해결책을 제공 할 수 있지만 왜 / 어떻게 작동하는지에 대한 컨텍스트를 추가하는 것이 좋습니다. 이것은 미래의 사용자가 자신의 코드를 배우고 적용 할 수 있도록 도와줍니다. 또한 코드를 설명 할 때 사용자의 의견을 공감 형태로 긍정적 인 피드백을받을 가능성이 있습니다.
borchvm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.