I'm new to android studio and I want to animate an imageButton with a sequential animation set. The animation set (animation_boutons.xml)is in res/anim.
I've tried with animationSet in java but the app crashed every time I launched the emulator.
I've spent a long time looking for a solution. I hope someone can help me !
I apologize if it's something obvious.
java code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
configureCodeurBouton();
}
private void configureCodeurBouton() {
ImageButton boutonCodeur = findViewById(R.id.boutoncodeur);
Animation animBoutons = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_boutons);
animBoutons.setRepeatCount(Animation.INFINITE);
boutonCodeur.setAnimation(animBoutons);
boutonCodeur.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, codeur.class));
}
});
}
}
xml code:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true"
android:fillAfter="true">
<rotate
android:fromDegrees="0"
android:toDegrees="20"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="0"
android:duration="1000"
/>
<rotate
android:startOffset="1000"
android:fromDegrees="20"
android:toDegrees="-20"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"
/>
<rotate
android:fromDegrees="-20"
android:toDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="3000"
android:duration="1000"
/>
</set>
Also, Vedprakash Wagh give me the advice to try animBoutons.setRepeatCount(Animation.INFINITE) but it has no effect).
Your app is crashing every time because you're trying to find your ImageButton when the class is created first, and not after the layout is set.
You're getting NullPointerException, as there is no ImageButton with id R.id.boutoncodeur in your View hierarchy when you're trying to find it.
You need to find your ImageView AFTER it is available in your View hierarchy i.e. after your setContentView();
You can either do this:
Remove your second line
ImageButton boutonCodeur = findViewById(R.id.boutoncodeur);
as you've already found your ImageView in your configureCodeurButton() function.
Or, you can keep one class variable of ImageView, and make findViewById call after setContentView like below.
public class MainActivity extends AppCompatActivity {
ImageButton boutonCodeur;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
boutonCodeur = findViewById(R.id.boutoncodeur);
configureCodeurBouton();
}
private void configureCodeurBouton() {
Animation animBoutons = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_boutons);
boutonCodeur.setAnimation(animBoutons);
boutonCodeur.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, codeur.class));
}
});
}
}
You can learn more about NullPointerException here. Also, learn how to read the errors from tutorials that are available. Or, simply open the logcat tab in Android Studio when the error occurs to know what Error you're getting.
To make your animation run infinitely, you can add this in your code.
animation.setRepeatCount(Animation.INFINITE)
I just had to change the whole xml anim_boutons file so I have only one animation and not three rotate animations. the repeatMode line says to repeat the animation backwards at each repeat. This gives the expected effect.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true"
android:fillAfter="true">
<rotate
android:fromDegrees="-20"
android:toDegrees="20"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="0"
android:duration="1000"
android:repeatCount="infinite"
android:repeatMode="reverse"
/>
</set>
I need to rotate the drawable resource of ImageButton. I've succeeded rotating functionality to my Button but rotating functionality affect whole button. All I want to do is rotate only drawable inside ImageButton.
How to handle this situation ?
PS: I accessed drawable inside ImageButton but I wasn't able give any animation functionality.
Thanks in helpings
Here my ImageButton xml;
<ImageButton
android:id="#+id/button"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="-40dp"
android:background="#color/titlebackground_color"
android:src="#drawable/open" />
Rotate first xml;
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<rotate
android:fromDegrees="-180"
android:toDegrees="-360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="500"
android:startOffset="0"
/>
</set>
Rotate Second xml;
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<rotate
android:fromDegrees="-180"
android:toDegrees="-0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="500"
android:startOffset="0"
/>
</set>
Animation functionality;
public class LayerInfoFragment extends Fragment {
int count = 0;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.layer_info_main, container, false);
btnClose = (ImageButton) v.findViewById(R.id.button);
btnClose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Animation rotate = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_first);
Animation rotatex = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_last);
if (count % 2 == 0) {
v.setRotation(180);
v.setAnimation(rotate);
} else {
v.setRotation(0);
v.setAnimation(rotatex);
}
count++;
}
});
}
}
There are 2 things to try I think.
1) Add code v.startAnimation(rotate); after v.setAnimation(). I suspect your animation never got started. I was thinking before that android:startOffset in the settings would trigger a start but that is not clear to me.
2) Try RotateAnimation, a direct subclass of Animation, instead of Animation objects. It seems many used RotateAnimation more than anything else. Besides that, the other issue I suspect is in the layout file.
Example:
RotateAnimation rotate = (RotateAnimation) AnimationUtils.loadAnimation...
Tell us what happens.
I'd like to apply 2 alternate rotation animations to a View. Each rotation should start after the click on the same View.
The result I'm looking for is:
the user clicks on the View and it rotates from 0° to 135°
the user clicks again on the View and it rotates from 135° to 0° (to the initial state)
The problem is that, when the user performs the second click, the Button resets to the initial aspect before starting the animation correctly.
I'm targeting Android APIs<11 so I'm using the startAnimation() method. The animations are applied to a Button view defined as follows:
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
The animations are the following
rotate_cw.xml (0° to 135° rotation):
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<rotate
android:duration="300"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="135" />
</set>
rotate_ccw.xml (135° to 0° rotation):
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:duration="300"
android:fromDegrees="135"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="0"/>
</set>
The animations are then applied in this way, where flag is a boolean global variable:
Button b = (Button) findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (flag) {
Animation a = AnimationUtils.loadAnimation(this, R.anim.rotate_cw);
b.startAnimation(a);
} else {
Animation a = AnimationUtils.loadAnimation(this, R.anim.rotate_ccw);
b.startAnimation(a);
}
flag = !flag;
}
});
Am I missing anything?
Thanks in advance for your help.
here is xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="150dp"
android:layout_height="match_parent">
<Button
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
here is java code
private Button text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (Button)findViewById(R.id.textview);
text.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
text.startAnimation(getScaleAnimation());
}
});
}
private ScaleAnimation getScaleAnimation(){
ScaleAnimation animation = new ScaleAnimation(1f,1.2f,1f,1.2f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation.setDuration(1000);
animation.setFillAfter(true);
return animation;
}
I am performing a simple ScaleAnimation on a Button.Is there any way I can get the animated view?
Just open anim folder inside res folder. Create an xml file. Then you need to create set tag. Inside of it, you can create scale tag.
Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_interpolator">
<scale
android:fromXScale="0.5"
android:toXScale="2"
android:fromYScale="0.5"
android:toYScale="2"
android:pivotX="50%"
android:pivotY="50%"
android:duration="5000"
/>
</set>
Note: do not forget to include xmlns:android declaration.
Now, inside of onCreate method or wherever you want, just put following. I am animating(scaling) a button itself when it is clicked:
Button but = (Button) findViewById(R.id.button1);
but.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Animation anim = AnimationUtils.loadAnimation(AnimationActivity.this, R.anim.animation);
but.startAnimation(anim);
}
});
EDIT:
in case you want to rotate it while scaling, you can put following inside of the xml file:
<rotate
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="5000"
/>
Hope this helps.
Use this way
Create an xml inside /res/anim folder and put the below code into it.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<scale android:fromXScale="0.0" android:fromYScale="0.0"
android:toXScale="1.0" android:toYScale="1.0"
android:duration="700" android:fillBefore="false" />
</set>
Place the below code inside the java file:
Animation scaleAnimation
= AnimationUtils.loadAnimation(this, R.anim.logoanimation);
Btn.startAnimation(scaleAnimation);
logoanimation is the name of my animation xml file.
for more refer this tutorial
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" />
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" />
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));
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" />
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>
To make shake effect like this
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));
}
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>
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();
/**
*
* #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
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.
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);
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()
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
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.
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);
}
}