I have a simple activity that spins an arrow to a random angle, and when the arrow stops spinning it flashes. The flashing effect is an alpha animation applied to an imageview of a lit version of the arrow.
It works just fine in Lollipop and above, but in KitKat when the alpha animation is applied it negates the setFillAfter of the completed rotation animation and the arrows instantly change to pointing straight up (0 degrees)
public void Spin2 ()
{
spinning = true;
degreeEnd = rnd.nextInt(360);
RotateAnimation spinIt = new RotateAnimation(0,3600+degreeEnd, RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);
spinIt.setDuration(6000);
spinIt.setFillAfter(true);
spinIt.setInterpolator(new DecelerateInterpolator());
spinIt.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
arrowLit.setVisibility(View.VISIBLE);
animBlink = new AlphaAnimation(1,0);
animBlink.setDuration(500);
animBlink.setInterpolator(new AccelerateInterpolator() );
animBlink.setRepeatCount(Animation.INFINITE);
// in KitKat this animation seems to reset the rotation..
arrowLit.startAnimation(animBlink);
spinning = false;
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
theSpinner.startAnimation(spinIt);
}
Interestingly, when you start the spinning again it flicks back to where it should be (degreeEnd) and starts the spin from there.
It is like it is temporarily overriding the setFillAfter of the rotation. I have tried various combinations of setFillBefore etc on the animations. Also, if I set the blinking animation to a finite number (eg 4) it will stop and stay at the zero - it won't correct until i re-spin.
Again, this works just fine in API 20 and up.
Thanks for any help
Andy
It seems to be something to do with the Frame Layout. Once it was out of the equation it works fine on KitKat.
Related
I am developing two different animations as shown below.
The first animation I was able to develop using Object animator and FrameLayout. Basically, I created the two rectangles and the candlesticks inside a gravity-centered frame layout. When made to start the animation, I used the object animator to move them on either side and return to the initial position.
My second animation is the issue point here. In this animation, the rectangles will go on a circular path from their initial point and return back to their initial point. During this course, the candles need to move in sync with the rectangle giving a spring effect (or) kind of a sliced rectangle.
My initial idea was to re-use the first animation and just as the first animation runs, I would run a rotate animation on the frameLayout view.
But that doesn't seem to work wherein rotation works but the translation doesn't.
Can someone say if I have taken the right approach or should I use some other way to achieve this?
Adding the code that I have tried, but didn't work.
Animation anim = new RotateAnimation(0.0f, 360.0f, pivotX, pivotY);
anim.setDuration(500);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
for(View view : mCandleSticks) {
ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "translationX", view.getX(), targetPos, view.getX());
anim1.setDuration(500);//set duration
anim1.start();//start animation
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
});
frameLayout.startAnimation(anim);
Thanks in advance.
I have an Activity with a toolbar (which is part of the SharedElements Activity entering animation) and below that toolbar are three ImageViews horizontally next to each other. In their XML implementation all three are set INVISIBLE.
What I'm trying to do is, to animate them sequentially "dropping" from behind the toolbar. My implemenation is this:
int delay = 500;
for (int y = 0; y < 3; y++) {
ObjectAnimator oa = ObjectAnimator.ofFloat(imageViews[y],
"translationY", -300, 0);
oa.setDuration(600);
oa.setStartDelay(delay);
oa.start();
imageViews[y].setVisibility(View.VISIBLE);
delay = delay+100;
}
}
As you can see, I'm iterating through the three ImageViews and start a animation for each one to go from a -300 X-position (which is behind the toolbar) to their normal position.
This animation works great - just as I want it to be, but the problem is, that right before all ImageViews are briefly flickering which I can't explain. I tried debugging, but while I'm going through the lines of that part my screen stays black. So I can't determine where/why the Views become visible.
Maybe you can help me to find my mistake.
Thank you, this is my working Code:
For all three ImageViews:
ObjectAnimator anim1Pin = ObjectAnimator.ofFloat(img_pinned, "translationY", -300, 0);
anim1Pin.setDuration(ANIMATON_DURATION);
anim1Pin.setStartDelay(300);
anim1Pin.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
img_pinned.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
And the AnimatorSet:
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(anim1Pin, anim2Alarm, anim3LED);
animatorSet.start();
Few things, first, the problem may be as simple as setting the visiblity state to GONE and then after animation starts, setting it to visible. However, I would also use AnimatorSet to play the animations together and add the delay rather than do it in a loop.
If you use AnimatorSet there is an onAnimationStart method in AnimationListener that you can use the set the visible to VISIBLE rather than do it how you have to ensure that they become visible at the right time.
I encountered this annoying problem, where I have 2 fragments, and I am running 3d flip animation on Fragments getView() component. Problem comes here, when the flip is done, I try to set another view invisible, but nothing happens. It seems that the animation is still on for the view and if I setAnimation(null) or clearAnimation for the view, the whole view is reset to start state.
I also did a little test, with just running alpha animation for the view and after that I cannot change the view visibility anymore. Any solution or hack for this kind of problem?
Thanks.
Here is small code snippet to reproduce problem.
Following code is ran when Fragment onCreateView has been called and button is clicked:
AlphaAnimation fadeHalf = new AlphaAnimation(1, 0.5f);
fadeHalf.setFillAfter(true);
fadeHalf.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
getView().setVisibility(View.GONE);
});
getView().startAnimation(fadeHalf);
So when running the code above, whole fragment view gets translated to 0.5f alpha, but setVisilibity(View.GONE) does nothing.
not sure if this is what you need but you can probably remove the view and add it back on when you do the same animation in the future.
I am trying to implement something relatively simple in ADNROID. I have a bunch of Drawables stored in a list. I want to create an effect where the drawables are displayed on top of each other, one by one, using a fade-in effect.
I have had partial success with the code below. It actually works flawlessly on my phone (Nexus S), but it shows flickering on my tablet (ASUS TF101). This is probably due to the fact that the tablet has a faster CPU.
Here is my setup: I have stored all the Drawables in the drawables list. I have also defined two images in my layout, one on top of the other: imageViewForeground and imageViewBackground.
The idea is to set the background image first, then start an animation where the foreground image starts from alpha-0 and goes to alpha-1. Then replace the background with the new foreground image, choose a new foreground (i.e. the next drawable) and loop forever.
The counter object is a simple wrapper for an int counter.
Here is my code:
final Animation fadeInAnimation = new AlphaAnimation(0f, 1f);
fadeInAnimation.setDuration(2000);
fadeInAnimation.setStartOffset(3000);
fadeInAnimation.setFillBefore(false);
fadeInAnimation.setFillAfter(true);
fadeInAnimation.setRepeatCount(Animation.INFINITE);
fadeInAnimation.setRepeatMode(Animation.RESTART);
fadeInAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
imageViewForeground.setImageDrawable(drawables.get(counter.value()));
Log.d(TAG, "onAnimationStart");
}
#Override
public void onAnimationEnd(Animation animation) {
Log.d(TAG, "onAnimationEnd");
}
#Override
public void onAnimationRepeat(Animation animation) {
imageViewBackground.setImageDrawable(drawables.get(counter.value()));
counter.increase();
// the problem appears in this line,
// where the foreground becomes visible for a very small period,
// causing the flickering
imageViewForeground.setImageDrawable(drawables.get(counter.value()));
}
});
imageViewForeground.startAnimation(fadeInAnimation);
Any ideas how I can overcome this flickering problem?
I've got a PopupWindow that's using an alpha animation to produce a fade-in display of the window.
Using PopupWindow.setAnimationStyle() works as expected: the popup fades-in when shown.
However, once the popup is displayed (meaning the fade-in animation has completed) I'd like to kick off another animation.
I've tried using the following to obtain the underlying animation that's referred to via setAnimationStyle() and attach an AnimationListener to it:
Animation fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.popup_fade_in);
fadeInAnimation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
Log.d(TAG, "fade-in animation START");
}
#Override
public void onAnimationEnd(Animation animation) {
Log.d(TAG, "fade-in animation END");
// Kick off the next animation
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
This does't work: None of the AnimationListener methods ever get called.
Anyone know of a way to determine when a popup window's animation has ended?
Alternatively, if there's a way to determine when the popup window has initially become visible I could kick off the secondary animation at that time. Unfortunately, I'm not finding anything in the API docs indicating how to do this.
Appreciate the help!