简体   繁体   中英

Animate ImageView using translation and rotation

I made my own way to animate the ImageView, but I'm pretty sure that there's a better approach that is short and won't cause a memory leak when the activity is destroyed.

The code that animates the image:


 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        floatImage(true, imageView);
    }

private void floatImage(boolean isRotating, View view) {
        if (isRotating) {
            shadAnim(view, "rotation", 5, 4000);
            new Handler(Looper.getMainLooper()).postDelayed(() -> {
                shadAnim(view, "rotation", -5, 4000);
                new Handler(Looper.getMainLooper()).postDelayed(() -> floatImage(true, view), 4000);
            }, 3500);
        } else {
            shadAnim(view, "translationY", -50, 3000);
            new Handler(Looper.getMainLooper()).postDelayed(() -> {
                shadAnim(view, "translationY", 0, 3000);
                new Handler(Looper.getMainLooper()).postDelayed(() -> floatImage(false, view), 3000);
            }, 3000);
        }
    }

 private void shadAnim(View view, String propertyName, double value, int duration) {
        ObjectAnimator anim = new ObjectAnimator();
        anim.setTarget(view);
        anim.setPropertyName(propertyName);
        anim.setFloatValues((float) value);
        anim.setDuration(duration);
        anim.start();
    }

This way works as intended but I'm asking if there's a better way to do it. Moreover, won't cause this memory leak:

┬───
    │ GC Root: System class
    │
    ├─ android.app.ActivityThread class
    │    Leaking: NO (MessageQueue↓ is not leaking and a class is never leaking)
    │    ↓ static ActivityThread.sMainThreadHandler
    ├─ android.app.ActivityThread$H instance
    │    Leaking: NO (MessageQueue↓ is not leaking)
    │    ↓ Handler.mQueue
    ├─ android.os.MessageQueue instance
    │    Leaking: NO (MessageQueue#mQuitting is false)
    │    HandlerThread: "main"
    │    ↓ MessageQueue[0]
    │                  ~~~
    ├─ android.os.Message instance
    │    Leaking: UNKNOWN
    │    Retaining 101 B in 3 objects
    │    Message.what = 0
    │    Message.when = 571932311 (1090 ms after heap dump)
    │    Message.obj = null
    │    Message.callback = instance @317197168 of com.project.app.MainActivity$$ExternalSyntheticLambda4
    │    Message.target = instance @315951112 of android.os.Handler
    │    ↓ Message.callback
    │              ~~~~~~~~
    ├─ com.project.app.MainActivity$$ExternalSyntheticLambda4 instance
    │    Leaking: UNKNOWN
    │    Retaining 12 B in 1 objects
    │    f$0 instance of com.project.app.MainActivity with mDestroyed = true
    │    ↓ SettingsActivity$$ExternalSyntheticLambda4.f$0
    │                                                 ~~~
    ╰→ com.project.app.MainActivity instance
    ​     Leaking: YES (ObjectWatcher was watching this because com.project.app.MainActivity received
    ​     Activity#onDestroy() callback and Activity#mDestroyed is true)
    ​     Retaining 1.2 MB in 3534 objects
    ​     key = 701a92c3-d630-4d18-89a4-47b9e79b8734
    ​     watchDurationMillis = 8268
    ​     retainedDurationMillis = 3263
    ​     mApplication instance of android.app.Application
    ​     mBase instance of androidx.appcompat.view.ContextThemeWrapper

The better option would be to

  1. define your animation in xml.
  2. Load it using AnimationUtils library.
  3. Attach the animation to the view.

Step 1: Create a new animation resource file. (res/anim/mySuperAnimation.xml)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
    android:interpolator="@android:anim/linear_interpolator"
    <-- Fine tune the parameters according to your needs -->
    android:duration="300" 
    android:fromYDelta="5" 
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:toYDelta="-5" />
</set>

Step 2: Load the created mySuperAnimation.xml file to your animator object.

Animation mAnimation = AnimationUtils.loadAnimation(getContext(),R.anim.mySuperAnimation);

Step 3: Link the animation to the view.

ImageView view = find(...);
view.startAnimation(mAnimation);

To stop the animation you have to call clearAnimation() on the animating view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM