Android animation "blink" when repeat - android

In my application I have this animation
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:shareInterpolator="true">
<alpha
android:duration="1000"
android:startOffset="2000"
android:fromAlpha="0"
android:toAlpha="1"/>
<scale
android:duration="400"
android:startOffset="4000"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.9"
android:toYScale="0.9"/>
<scale
android:duration="400"
android:startOffset="4400"
android:fromXScale="0.9"
android:fromYScale="0.9"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1"
android:toYScale="1"/>
<alpha
android:duration="1000"
android:startOffset="5800"
android:fromAlpha="1"
android:toAlpha="0"/>
</set>
Generally it shows image, make "press" gesture and hide it. What I want is run this animation in infinite loop. Setting parameter repeatCount doesn't work. Only way I found is to start animation again in animation listener.
final Animation pointerAnim = AnimationUtils.loadAnimation(this, R.anim.pointer);
pointerAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(final Animation animation) {}
#Override
public void onAnimationEnd(final Animation animation) {
pointerView.startAnimation(pointerAnim);
}
#Override
public void onAnimationRepeat(final Animation animation) {}
});
pointerView.startAnimation(pointerAnim);
But here comes my problem. Between end and new start animation, the image "blink" (appeared and disappeared in short moment) and I don't know how to prevent this. Using fillAfter doesn't work. Also setting appropriate visibility in listener doesn't work. Note that target API is 10.
I'll be glad for any advice

This was surprisingly tricky, but here's an answer that seems to work and avoid the blinking. Break the animation up into two parts and set two animation listeners so that when each of them finish, they trigger the other one to start. It looks as follows:
pointer_fade_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:shareInterpolator="true">
<alpha
android:duration="1000"
android:startOffset="2000"
android:fromAlpha="0"
android:toAlpha="1"/>
<scale
android:duration="400"
android:startOffset="4000"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.9"
android:toYScale="0.9"/>
</set>
pointer_fade_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="400"
android:startOffset="0"
android:fromXScale="0.9"
android:fromYScale="0.9"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1"
android:toYScale="1"/>
<alpha
android:duration="1000"
android:startOffset="1400"
android:fromAlpha="1"
android:toAlpha="0"/>
</set>
Then the code:
final Animation pointerFadeInAnim = AnimationUtils.loadAnimation(this, R.anim.pointer_fade_in);
final Animation pointerFadeOutAnim = AnimationUtils.loadAnimation(this, R.anim.pointer_fade_out);
pointerFadeInAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(final Animation animation) {}
#Override
public void onAnimationEnd(final Animation animation) {
pointerView.startAnimation(pointerFadeOutAnim);
}
#Override
public void onAnimationRepeat(final Animation animation) {}
});
pointerFadeOutAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
pointerView.startAnimation(pointerFadeInAnim);
}
#Override
public void onAnimationRepeat(Animation animation) {}
});
pointerView.startAnimation(pointerFadeInAnim);
Hope this works for you!

Did you try combining both repeatMode and repeatCount attributes like in the following example
<scale
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000"
android:repeatCount="infinite"
android:repeatMode="restart"
/>
Hope it has helped

Maybe it's just a workaround that won't be applicable in your case, but would it be possible to offset the entiere animation, so that it starts at 3000 ? (Thus, when alpha=1.0)
(Well, after some thought, I'm pretty sure you can't do that, because the alpha transition should be the first when the object first appears on screen)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:shareInterpolator="true">
<scale
android:duration="400"
android:startOffset="1000"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.9"
android:toYScale="0.9"/>
<scale
android:duration="400"
android:startOffset="1400"
android:fromXScale="0.9"
android:fromYScale="0.9"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1"
android:toYScale="1"/>
<alpha
android:duration="1000"
android:startOffset="2800"
android:fromAlpha="1"
android:toAlpha="0"/>
<alpha
android:duration="1000"
android:startOffset="5800"
android:fromAlpha="0"
android:toAlpha="1"/>
</set>

Related

Android animation scale onEnd blink

I have problem with scale in animation. Translate works fine, but when I add scale to my animation it dont come back to point of start and blink when animation starts again.
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<translate
android:fromYDelta="-150"
android:toYDelta="150"
android:fillAfter="true"
android:duration="1500"
/>
<scale
android:fillAfter="true"
android:fromXScale="1"
android:fromYScale="1"
android:toXScale="1.2"
android:toYScale="1.2"
android:duration="1500"
android:pivotX="50%"
android:pivotY="50%"
/>
</set>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<translate
android:fromYDelta="150"
android:toYDelta="-150"
android:fillAfter="true"
android:duration="1500"
android:startOffset="1500"
/>
<scale
android:fillAfter="true"
android:fromXScale="1.2"
android:fromYScale="1.2"
android:toXScale="1"
android:toYScale="1"
android:duration="1500"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="1500"
/>
</set>
And Android code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
image.setImageResource(R.drawable.shape);
animation2 = AnimationUtils.loadAnimation(this, R.anim.moving_up);
animation3 = AnimationUtils.loadAnimation(this, R.anim.moving_down);
animation = new AnimationSet(true);
animation.addAnimation(animation2);
animation.addAnimation(animation3);
animation.setAnimationListener(this);
//animation.setRepeatCount(Animation.INFINITE);
animation.setFillEnabled(true);
animation.setFillAfter(true);
image.startAnimation(this.animation);
}
#Override
public void onAnimationEnd(Animation animation) {
image.clearAnimation();
image.startAnimation(animation);
}
Shape is a xml Rect.
animation.setFillAfter(true);
will force the image to stay at animated position after animation gets completed.
Set it to false if you want to return the image to starting position.
animation.setFillAfter(false);
If someone would like to know the answer
private void animateImage(){
float x = 1;
float scale = 1.1f;
x = (imageViewImage.getHeight()*1.1f - imageViewImage.getHeight())/2;
imageViewImage.animate().translationY(x).scaleX(scale).scaleY(scale).setDuration(8000).withEndAction(new Runnable() {
#Override
public void run() {
imageViewImage.animate().translationY(0).scaleX(1f).scaleY(1f).setDuration(8000).withEndAction(new Runnable() {
#Override
public void run() {
animateImage();
}
});
}
});
}

AnimationSet defined via XML does not repeat

I have this xml code, that should simulate a sort of "heart beat" animation. Image that use it should scale twice, and return to original size, then restart again:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:repeatCount="-1"
android:repeatMode="restart"
android:shareInterpolator="true" >
<scale
android:duration="500"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.2"
android:toYScale="1.2" />
<scale
android:duration="500"
android:fromXScale="1.2"
android:fromYScale="1.2"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.4"
android:toYScale="1.4" />
<scale
android:duration="500"
android:fromXScale="1.4"
android:fromYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
and this is how i add this animation set to my imageview:
AnimationSet heart_pulse = new AnimationSet(true);
heart_pulse.addAnimation(AnimationUtils.loadAnimation(activity,
R.anim.pulsexml));
logo.setAnimation(heart_pulse);
logo.startAnimation(heart_pulse);
but animation is executed only one time, then it stops. Why?
try this custom Interpolator:
final ImageView iv = new ImageView(this);
iv.setImageResource(R.drawable.heart);
setContentView(iv);
Runnable action = new Runnable() {
#Override
public void run() {
Interpolator i = new Interpolator() {
#Override
public float getInterpolation(float input) {
float x = input < 1/3f? 2 * input : (1 + input) / 2;
return (float) Math.sin(x * Math.PI);
}
};
ScaleAnimation anim = new ScaleAnimation(1, 1.2f, 1, 1.2f, iv.getWidth() / 2, iv.getHeight() / 2);
anim.setRepeatCount(Animation.INFINITE);
anim.setDuration(750);
anim.setInterpolator(i);
iv.startAnimation(anim);
}
};
iv.post(action);
Have you tried adding android:fillAfter="false"?
EDIT:
According to the documentation sintax of Animation, these properties must be set to an Animatior and not to the set, so let's have then this custom animation repeating with no code:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="500"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="restart"
android:toXScale="1.2"
android:toYScale="1.2" />
<scale
android:duration="500"
android:fromXScale="1.2"
android:fromYScale="1.2"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="restart"
android:toXScale="1.4"
android:toYScale="1.4" />
<scale
android:duration="500"
android:fromXScale="1.4"
android:fromYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="restart"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
Consider using a CycleInterpolator for your animation, e.g.:
final Animation animation = AnimationUtils.loadAnimation(context, R.anim.pulsexml);
animation.setInterpolator(new CycleInterpolator(3f));
logo.startAnimation(animation);

Unsmooth, lagging animation in android

I have used animation on an activity in my game where user sees his score in form of stars(maximum score gets 3 stars). I have used animation on each of the stars(using startAnimation() method). The golden stars gets placed on the blank grey colored stars with translation, scale and alpha animation(I have used set animation).
But whenever that score activity starts the animation gets displayed with jerkiness/lag/unsmoothness.
Whats the solution to make that animation smooth and timely?
Following is the java code to dislplay 3 out of 3 stars
protected void onCreate(Bundle savedInstanceState)
{
............
Myanim1 = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.alpha_scale_left);
Myanim2= AnimationUtils.loadAnimation(getApplicationContext(), R.anim.aplha_scale_mid);
Myanim3= AnimationUtils.loadAnimation(getApplicationContext(), R.anim.alpha_scale_right);
......}
if(pattern_Score>targetScore*90/100)
{
mCountDownTimer = new CountDownTimer(1000,100) {
#Override
public void onTick(long millisUntilFinished) {
starIv1.setImageResource(R.drawable.star_gray);
}
#Override
public void onFinish() {
starIv1.startAnimation(Myanim1);
starIv1.setImageResource(R.drawable.star);
Toast.makeText(getApplicationContext(), "timer1 stopped", Toast.LENGTH_SHORT).show();
}
};
mCountDownTimer.start();
starIv1.clearAnimation();
mCountDownTimer1=new CountDownTimer(2000,100) {
#Override
public void onTick(long millisUntilFinished) {
starIv2.setImageResource(R.drawable.star_gray);
}
#Override
public void onFinish() {
//starIv2.clearAnimation();
starIv2.startAnimation(Myanim2);
starIv2.setImageResource(R.drawable.star);
}
};
mCountDownTimer1.start();
starIv2.clearAnimation();
mCountDownTimer2=new CountDownTimer(3000,100) {
#Override
public void onTick(long millisUntilFinished) {
starIv3.setImageResource(R.drawable.star_gray);
}
#Override
public void onFinish() {
//starIv3.clearAnimation();
starIv3.startAnimation(Myanim3);
starIv3.setImageResource(R.drawable.star);
}
};
mCountDownTimer2.start();
starIv3.clearAnimation();....}
alpha_scale_left.xml(animation on left star)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="-100%"
android:fromXDelta="-20%"
android:toYDelta="0"
android:toXDelta="0"
android:duration="600"/>
<scale
android:fromXScale="3000%"
android:fromYScale="3000%"
android:toXScale="1"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:duration="900"
/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="600" />
</set>
alpha_scale_mid.xml(animation on middle star)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="-100%"
android:fromXDelta="-5%"
android:toYDelta="0"
android:toXDelta="0"
android:duration="600"/>
<scale
android:fromXScale="3000%"
android:fromYScale="3000%"
android:toXScale="1"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="0%"
android:duration="600"
/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="600" />
</set>
alpha_scale_right.xml(animation on right star)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="-100%"
android:fromXDelta="5%"
android:toYDelta="0"
android:toXDelta="0"
android:duration="600"/>
<scale
android:fromXScale="3000%"
android:fromYScale="3000%"
android:toXScale="1"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="0%"
android:duration="600"
/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="600" />
</set>
I don't understand the meaning of 3000% in your xmls try changing in the range of ~100%
Looking at the code I can suggest you to use some threads and not load all the animations on the main thread and you should rather use Asynctask and based on some progress you may use onprogressupdate method to make changes to the UI thread.
OR
Graphics and Animations are handled by the GPU or in more common
term the Processor of your device. If not rendered properly then it
could possibly be the result of a processor with low clock rate.

Scale Animation doesn't affect layout

I have top_sliding_out animation defined like that:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator" >
<alpha
android:duration="300"
android:fromAlpha="1"
android:toAlpha="0" />
<scale
android:duration="300"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="0%"
android:toXScale="1"
android:toYScale="0" />
</set>
Code triggering animation:
public void onCheckedChanged(final CompoundButton buttonView, boolean isChecked)
{
Animation anim = AnimationUtils.loadAnimation(this.getActivity(), R.anim.top_slide_out);
anim.setFillAfter(true);
((View)buttonView.getParent()).startAnimation(anim);
final Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
public void run()
{
getListView().requestLayout();
}
}, anim.getDuration());
}
I perform this animation to hide my custom row in a list. But the problem is that layout doesn't change it's size, so it is left with empty hole.
Before animation:
After animation:
What can I do about that? How can I change layout when animation is in progress?

Android: FillAfter not working for ScaleAnimation in ImageView

I am applying three animations in an ImageView, one after another. I have a AnimationListener for each animation, so inside the onAnimationEnd, I start the next one, so they dont overlap. The animations are this: scale in, fade out and the last one fade in. The fade in animation will restart the scale in animation again, to these animations will be running "forever". What I am trying to achieve is the same effect Twitter has applied to their new home screen, where they keep changing the pictures.
The problem with my animations is that after scaling in the ImageView and before staring the the fade out animation, the ImageView gets reseted and the scale change is lost, even setting fillAfter in the code or in the xml file. Here is the code for handling the animation events:
mAnimationFadeIn = AnimationUtils.loadAnimation(this, R.anim.fade_in);
mAnimationFadeIn.setFillAfter(true);
mAnimationFadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);
mAnimationFadeOut.setFillAfter(true);
mAnimationScaleIn = AnimationUtils.loadAnimation(this, R.anim.slow_scale_in);
mAnimationScaleIn.setFillAfter(true);
mAnimationScaleIn.setFillEnabled(true);
mAnimationScaleIn.setFillBefore(false);
mAnimationScaleIn.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
mImageView.startAnimation(mAnimationFadeOut);
}
});
mAnimationFadeOut.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
mImageView.setImageResource(mImages[++mImageIndex > 2 ? mImageIndex=0 : mImageIndex]);
mImageView.startAnimation(mAnimationFadeIn);
}
});
mAnimationFadeIn.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
mImageView.startAnimation(mAnimationScaleIn);
}
});
mImageView.startAnimation(mAnimationScaleIn);
and here are my animations:
scale in:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:duration="9000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:toXScale="1.1"
android:toYScale="1.1" />
fade in:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="0.0"
android:interpolator="#android:anim/linear_interpolator"
android:toAlpha="1.0" />
fade out:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1.0"
android:interpolator="#android:anim/linear_interpolator"
android:toAlpha="0.0" />
Is there a way to keep the scale transformation before starting the fade out animation?
I have tried all the combinations for setFillAfter, setFillBefore and setFillEnabled and no way I can get the scale transformation to be kept after the scale animation is over.
Many thanks
T
do as given below u have to enable it in set tag and than use in either rotate or scale etc...
<?xml version="1.0" encoding="UTF-8"?>
<set android:shareInterpolator="false"
android:fillEnabled="true"
android:fillAfter="true"
xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="359"
android:pivotX="50%"
android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="1.4"
android:pivotY="50%"
android:fillAfter="true"
android:fillEnabled="true"
android:duration="2000" />
<scale
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"
android:fillEnabled="true"
android:fillAfter="true"
android:duration="2000" />
</set>

Categories

Resources