shaking / wobble view animation in android

AndroidAndroid Animation

Android Problem Overview


I created an anim.xml file such as below to shake imageview like IOS icon shaking in android. However it does not provide me same result. Is there any better idea?

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

Android Solutions


Solution 1 - Android

Try setting android:repeatMode="reverse". Below animation gives a very reasonable immitation on my Galaxy Nexus. Obviously you can fine tune the parameters to your own liking.

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="100"
    android:fromDegrees="-5"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:toDegrees="5" />

Solution 2 - Android

Nice shake animation;

res/anim/shake.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate android:duration="150"
        android:fromXDelta="-10%"
        android:repeatCount="5"
        android:repeatMode="reverse"
        android:toXDelta="10%"/>
</set>

How to use it

final Animation animShake = AnimationUtils.loadAnimation(this, R.anim.shake);
btn_done = (Button) findViewById(R.id.btn_act_confirm_done); 
btn_done.startAnimation(animShake);

How to use it (Simpler version):

btn_done.startAnimation(AnimationUtils.loadAnimation(this,R.anim.shake));

Solution 3 - Android

You could try this:

shake.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android" 
           android:fromXDelta="0" 
           android:toXDelta="10" 
           android:duration="1000" 
           android:interpolator="@anim/cycle_7" />

cycle_7.xml

<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android" 
                   android:cycles="7" />

Solution 4 - Android

try to use this one:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:duration="70"
        android:fromDegrees="-5"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="5"
        android:repeatMode="reverse"
        android:interpolator="@android:anim/linear_interpolator"
        android:toDegrees="5" />
    <translate
        android:fromXDelta="-10"
        android:toXDelta="10"
        android:repeatCount="5"
        android:repeatMode="reverse"
        android:interpolator="@android:anim/linear_interpolator"
        android:duration="70" />
</set>

Solution 5 - Android

To make shake effect like this

enter image description here

First define shake animation inside anim folder as shake.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:duration="70"
        android:fromDegrees="-5"
        android:interpolator="@android:anim/linear_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="5"
        android:repeatMode="reverse"
        android:toDegrees="5" />
    <translate
        android:duration="70"
        android:fromXDelta="-10"
        android:interpolator="@android:anim/linear_interpolator"
        android:repeatCount="5"
        android:repeatMode="reverse"
        android:toXDelta="10" />
</set>

Then in code

if (TextUtils.isEmpty(phone.getText())
 || phone.getText().length() < 10)
    {
     //shake animation
    phone.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.shake));
     }
             

Solution 6 - Android

I created a shake effect on Android and posted in GitHub. See if it works better.

https://github.com/teoinke/ShakeAnimation

Relevant code:

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/overshoot_interpolator"
    android:fillAfter="true">

    <translate
        android:startOffset="100"
        android:fromXDelta="0%p"
        android:toXDelta="10%p"
        android:duration="50" />

    <translate
        android:startOffset="150"
        android:fromXDelta="0%p"
        android:toXDelta="-25%p"
        android:duration="110" />


    <translate
        android:startOffset="260"
        android:fromXDelta="0%p"
        android:toXDelta="25%p"
        android:duration="120" />


    <translate
        android:startOffset="380"
        android:fromXDelta="0%p"
        android:toXDelta="-20%p"
        android:duration="130" />


    <translate
        android:startOffset="510"
        android:fromXDelta="0%p"
        android:toXDelta="10%p"
        android:duration="140" />

</set>

Solution 7 - Android

This one works pretty well (though not perfectly) as an iOS "incorrect PIN" shaking clone:

    final float FREQ = 3f;
    final float DECAY = 2f;
    // interpolator that goes 1 -> -1 -> 1 -> -1 in a sine wave pattern.
    TimeInterpolator decayingSineWave = new TimeInterpolator() {
                @Override
                public float getInterpolation(float input) {
                    double raw = Math.sin(FREQ * input * 2 * Math.PI);
                    return (float)(raw * Math.exp(-input * DECAY));
                }
            };

    shakeField.animate()
            .xBy(-100)
            .setInterpolator(decayingSineWave)
            .setDuration(500)
            .start();

Solution 8 - Android

/**
 *
 * @param view      view that will be animated
 * @param duration  for how long in ms will it shake
 * @param offset    start offset of the animation
 * @return          returns the same view with animation properties
 */
public static View makeMeShake(View view, int duration, int offset) {
    Animation anim = new TranslateAnimation(-offset,offset,0,0);
    anim.setDuration(duration);
    anim.setRepeatMode(Animation.REVERSE);
    anim.setRepeatCount(5);
    view.startAnimation(anim);
    return view;
}

use:

TextView tv;
makeMeShake(tv,20,5);    // it will shake quite fast

Solution 9 - Android

For Kotlin users:

First create an Animation resource file called shake.xml. Right click on the res folder in Android Studio, then click New > Android Resource File > enter shake for the file name and select Animation for Resource type dropdown. Click OK.

Inside shake.xml paste the following:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:duration="200"
               android:fromXDelta="-5%"
               android:repeatCount="3"
               android:repeatMode="reverse"
               android:toXDelta="5%"/>
</set>

Now just call it on a view!

From within a fragment:

myView.startAnimation(AnimationUtils.loadAnimation(requireContext(), R.anim.shake))

From within an activity:

myView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake))

(note - myView is the ID given to the view that you want to animate)

If you would like to fine-tune the animation, simply modify the values in shake.xml.

Solution 10 - Android

I created a very good approximation of iOS shaking (when you long press a icon to remove app from homescreen). You have to apply inside your code, programmatically, as it requires random number generation:

int dur1 = 70 + (int)(Math.random() * 30);
int dur2 = 70 + (int)(Math.random() * 30);

// Create an animation instance
Animation an = new RotateAnimation(-3, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

// Set the animation's parameters
an.setDuration(dur1);               // duration in ms
an.setRepeatCount(-1);                // -1 = infinite repeated
an.setRepeatMode(Animation.REVERSE);
an.setFillAfter(true);               // keep rotation after animation


// Create an animation instance
Animation an2 = new TranslateAnimation(-TranslateAnimation.RELATIVE_TO_SELF,0.02f,
        TranslateAnimation.RELATIVE_TO_SELF,0.02f,
        -TranslateAnimation.RELATIVE_TO_SELF,0.02f,
        TranslateAnimation.RELATIVE_TO_SELF,0.02f);

// Set the animation's parameters
an2.setDuration(dur2);               // duration in ms
an2.setRepeatCount(-1);                // -1 = infinite repeated
an2.setRepeatMode(Animation.REVERSE);
an2.setFillAfter(true);               // keep rotation after animation

AnimationSet s = new AnimationSet(false);//false means don't share interpolators
s.addAnimation(an);
s.addAnimation(an2);

// Apply animation to image view
itemView.setAnimation(s);

This code was design to be applied inside an adapter's gridview (getView), but you can apply to any view by changing the last line to:

yourViewName.setAnimations(s);

Solution 11 - Android

Kotlin version of lincolnq's answer

val FREQ = 3f
val DECAY = 2f
            
val decayingSineWave = TimeInterpolator { input ->
   val raw = sin(FREQ * input * 2 * Math.PI)
   (raw * exp((-input * DECAY).toDouble())).toFloat()
}

// where binding.loginFrame is the view you wanna shake
binding.loguinFrame.animate()
 .withEndAction{
    // here you can clear the fields after the shake
 }
 .xBy(-100f)
 .setInterpolator(decayingSineWave)
 .setDuration(500)
 .start()

Solution 12 - Android

IOS wobble animation is not that simple try to change pivot x and y randomly when rotate. You should change the value programatically though. May be you also can use translate animation simultaneously

Solution 13 - Android

Banging my head for more than two hours, I knew how to shake and wobble an view.

Unfortunately the accepted answer won't work apart from onCreateView of fragment.

Example if you have onClick method and inside in it. You have animation like below it won't work.

Please go through the code.

    DoneStart.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View view) {
           register(view);

        }
    });

The register method has some checks like below code

 private void register(View view) {
    String type = typedThings.getText.toString(); 
   String  km = Km_Now.getText().toString();

    if (serviceType == null) {
        animationServiceList = AnimationUtils.loadAnimation(getActivity(), R.anim.shake_wobble);
        silverServiceButton.setAnimation(animationServiceList);
        generalServiceButton.setAnimation(animationServiceList);
        platinumServiceButton.setAnimation(animationServiceList);
        animationServiceList.start();
    } else if (km == null) {
        animationEditText = AnimationUtils.loadAnimation(getActivity(), R.anim.shake_wobble);
        Km_Now.setAnimation(animationEditText);
        animationEditText.start();
    }

The Call animationServiceList.start(); will never be called,

SOLUTION: Use PropertyAnimator like ObjectAnimator.

Solution 14 - Android

Other answers are correct as well but this is a bit smoother than them since it uses an interpolator produces smooth numbers for back an forth movement

    public class WobblyView extends ImageView implements ValueAnimator.AnimatorUpdateListener {
    private final ValueAnimator va = ValueAnimator.ofInt(-10, 10);

    public WobblyView(Context context) {
        this(context, null);
    }

    public WobblyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WobblyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setAdjustViewBounds(true);
        setImageResource(R.drawable.ic_logo);
        va.setInterpolator(new AccelerateDecelerateInterpolator());
        va.setRepeatMode(ValueAnimator.REVERSE);
        va.setRepeatCount(ValueAnimator.INFINITE);
        va.setDuration(1000);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        va.addUpdateListener(this);
        va.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        va.removeUpdateListener(this);
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int heading = (int) animation.getAnimatedValue();
        setRotation(heading);
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWinstonView Question on Stackoverflow
Solution 1 - AndroidMH.View Answer on Stackoverflow
Solution 2 - AndroidSamirView Answer on Stackoverflow
Solution 3 - AndroidadnealView Answer on Stackoverflow
Solution 4 - AndroidSimonView Answer on Stackoverflow
Solution 5 - AndroidHitesh SahuView Answer on Stackoverflow
Solution 6 - AndroidTeo InkeView Answer on Stackoverflow
Solution 7 - AndroidlincolnqView Answer on Stackoverflow
Solution 8 - AndroidWindlessView Answer on Stackoverflow
Solution 9 - AndroidJoeView Answer on Stackoverflow
Solution 10 - AndroidAdriano MoutinhoView Answer on Stackoverflow
Solution 11 - AndroidTadeoArmentaView Answer on Stackoverflow
Solution 12 - Androidwooram jungView Answer on Stackoverflow
Solution 13 - AndroidEngineSenseView Answer on Stackoverflow
Solution 14 - AndroidDeliganliView Answer on Stackoverflow