I'm trying to reuse AlphaAnimation object in a method of an Activity for every new MyView added every second to myLayout:
private AlphaAnimation showAnimation = new AlphaAnimation(0, 1);
private void addViewAndAnimate() {
MyView view = new MyView();
myLayout.addView(view);
showAnimation.setDuration(durationTime);
view.startAnimation(showAnimation);
}
but after I call addViewAndAnimate() the animation is not applied for latest added MyView only, but gets repeated for all MyViews added earlier.
Are view objects somehow bound to an animation? If so is there a way to detach them?
To remove animation from the View, use View.clearAnimation();
So you need to store somewhere a view, to which the animation is applied before, and clear it before applying it to new view. Also you can try to create a new Animation instance for each view.
Or start animation in Handler.post(). This shouldstart animation in the current view for sure
Related
I am using an expandable recycler view and I am trying to make a rotation animation on an ImageView that is a child of the ViewHolder. I set a click listener on the a certain button and in there I call the animateIconExpansion method that performs the animation:
private void animateIconExpansion(ImageView expandIcon, boolean isExpanded) {
ObjectAnimator animator = ObjectAnimator.ofFloat(this.expandIcon, "rotation", rotationEnd - 180f, rotationEnd);
animator.setDuration(1000);
animator.start();
}
The problem is that the animation doesn't work properly. I tried using the animate API introduced in 3.0 and it didn't work. I also tried the RotateAnimation and it didn't work:
RotateAnimation rotateAnim = new RotateAnimation(rotationEnd - 180f, rotationEnd,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotateAnim.setDuration(200);
rotateAnim.setFillBefore(true);
expandIcon.startAnimation(rotateAnim);
What am I doing wrong?
So the problem I was having is that I was making the animation in Adapter. Which was stated here as a wrong approach.
What we want to do in this case is to create a class that extends DefaultItemAnimator, override the animateChange method and place your custom animation there.
Now the problem with that is that you don't know the state of your view holder. Sometimes you want to animate the holder when a button is clicked. To solve that you can use flags in your view holder, that you will have a reference to in the animateChange method.
Then you'd want to call recyclerView.setItemAnimator(animater) and pass in an instance of your class.
I want to apply an animation for multiple views at the same time, how can I apply said animation to several types of views (buttons, imageviews, and other views)?
If what you want is to apply an animation on several views at the same time, simply call the startAnimation method on those views one after the other. They will be simultaneous
//Get your views
View view1 = findViewById(R.id.view1);
View view2 = findViewById(R.id.view2);
View view3 = findViewById(R.id.view3);
//Get your animation
Animation youranimation = AnimationUtils.loadAnimation(this, R.anim.animationid);
//Start animations
view1.startAnimation(youranimation);
view2.startAnimation(youranimation);
view3.startAnimation(youranimation);
Or if you have a lot of views:
Animation youranimation = AnimationUtils.loadAnimation(this, R.anim.animationid);
int[] viewIds = new int[]{R.id.view1,R.id.view2,R.id.view3,R.id.view4};
for(int id : viewIds) findViewById(id).startAnimation(youranimation);
That is, assuming you want to animate several views at the same time, if what your're doing is one after the other we would dive into animation listeners and that's another story
You may use object animators.
There is an easy example in that link which you can also use.
You may also use this tutorial.
Use ValueAnimator instead, and set views property in onAnimationUpdate.
mShowAnimator = ValueAnimator.ofFloat(0f, 1f);
mShowAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
for (View v : mTargetViews) {
v.setAlpha((Float)animation.getAnimatedValue());
}
}
});
You can create one large AnimatorSet() that includes several ObjectAnimators. This allows you to play all animations at the same time with no delay. See my answer here.
Trying to add a help overlay to our app.
This overlay is a RelativeLayout with translucent background and it contains a few TextView and a few ImageView child elements. Now, i want each of the TextView / ImageView to fade-in one after another.
I am using a fade-in animation set (defined in the XML) and calling .startAnimation() on each view in the AnimationListener's OnAnimationEnd method. So, when the first View is done fading-in, i call the startAnimation method on the next view to be faded-in. I am using the same Animation object (animationFadeIn) as argument to startAnimation of all the views. Like so:
...
Animation animationFadeIn = AnimationUtils.loadAnimation(this.context, R.anim.fadein);
...
AnimationListener animationInListener = new AnimationListener(){
#Override
public void onAnimationEnd(Animation animation) {
animation_activity++;
switch(animation_activity) {
case SHOW_TEXT_DROP:
txtDrop.startAnimation(animationFadeIn);
break;
case SHOW_TEXT_SEND:
txtSend.startAnimation(animationFadeIn);
break;
case SHOW_IMAGE_TOUCH:
imgTouch.startAnimation(animationFadeIn);
break;
case SHOW_TEXT_DISABLE:
txtDisable.startAnimation(animationFadeIn);
break;
}
}
};
For fade-in animation, i referred this tutorial
Now, here's the problem:
First view fades-in
Second view fades-in, but first view fades-in again as well along with it
Same continues until all the views are done fading-in
Also, how do i add some delay before the next view fades-in setStartOffset ?
UPDATE
I noticed that if i create a second Animation object by
animationFadeIn2 = AnimationUtils.loadAnimation(this.context, R.anim.fadein);
and then use it for the startAnimation of other element, then it does not create this issue. So, i believe, there must be some property to be set on the Animation object so as to avoid this ?
I finally went ahead and created multiple Animation objects for each of the element. That solves the issue for time-being. It may not be the right/best approach.
I'm trying to insert a View behind another view that is taking up the full screen and then later removing the view in the front to reveal the only remaining view. Functionally, everything is working as expected but the problem is that when I call View.addView() to add the second view, specifying to add it at index 0 so it is behind the first view, the screen flickers. It's almost as if the view is actually getting added in front of the first view for a fraction of a second and then it is hidden again as it is moved behind it.
Here's what I'm doing:
When the Activity is created I add an ImageView to a RelativeLayout and make the RelativeLayout instance the Activity's content view:
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
m_layout = new RelativeLayout(this);
m_layout.setBackgroundColor(Color.BLACK);
m_splashImage = new ImageView(this);
m_splashImage.setImageResource(R.drawable.splash);
m_splashImage.setScaleType(ScaleType.FIT_XY);
m_layout.addView(m_splashImage,
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
setContentView(m_layout);
}
When the Activity is started, I created and add the GLSurfaceView to the RelativeLayout at index 0, so it is behind the ImageView:
protected void onStart() {
super.onStart();
m_layout.addView(new MyGLSurfaceView(), 0,
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
}
Later, after all of the loading is done and the GLSurfaceView is ready to continuously render,
the splash ImageView is removed and cleaned up.
public void hideSplashScreen() {
if (m_splashImage != null) {
m_layout.removeView(m_splashImage);
m_splashImage = null;
}
}
Is there a better way to do this that doesn't require creating the GLSurfaceView before the onStart() is called?
Have you tried using view.setVisibility(View.GONE) on of the view that you adding behind? Of course before you are adding it.
I'm working on a game that requires drawing to SurfaceView's
Canvas. I'm using SurfaceHolder to obtain Canvas to draw to, and
perform drawing in a separate thread. Everything I draw displays
correctly except for this one animation.
Here is the animation definition (it is in res/drawable/
my_animation.xml:
and here is how I draw it to the Canvas:
AnimationDrawable ad = (AnimationDrawable)getResources().getDrawable(R.drawable.my_animation);
ad.draw(canvas);
ad.start();
but only the first frame ever appears on the screen.
What am I missing?
Thank you
If I get the reference right, you have to assign your AnimationDrawable to an ImageView as the example from http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html demonstrates:
// Load the ImageView that will host the animation and
// set its background to our AnimationDrawable XML resource.
ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
img.setBackgroundResource(R.drawable.spin_animation);
// Get the background, which has been compiled to an AnimationDrawable object.
AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();
// Start the animation (looped playback by default).
frameAnimation.start()
In your case you did not assign your AnimationDrawable to any view so I suppose that's why it does not get updated. So you have to call AnimationDrawable.getFrame(int) manually.
If you are already using a separate thread why don't you involve also the code for your animation? This would render your code more consistent in my opinion.
Although this is an old question, i run into this problem too and figure out a walkaround, so i just post it here in case anyone searching about.
```java
final AnimationDrawable animationDrawable = ...;
final View v = new View(this) {
#Override
protected void onDraw(Canvas canvas) {
animDrawable.draw(canvas);
}
};
animationDrawable.setCallback(new Callback() {
#Override
public void unscheduleDrawable(Drawable who, Runnable what) {
v.removeCallbacks(what);
}
#Overridew
public void scheduleDrawable(Drawable who, Runnable what, long when) {
v.postDelayed(what, when - SystemClock.uptimeMillis());
}
#Override
public void invalidateDrawable(Drawable who) {
v.postInvalidate();
}
});
```
Animated drawables of all kinds (Transition, etc.) need a Callback to schedule redrawals. As zhang demonstrates, it is a simple interface for posting Runnables.
To support animated drawables in a custom view, you need two things:
pass your View to your animated Drawable's setCallback. Even base View implements Drawable.Callback, so there's no need to write your own wrapper.
override verifyDrawable to also return true for your animated Drawable.
As to why anyone would need that - I have just implemented animated drawable support in RecyclerView.ItemDecorations, how cool is that :-)
You are working with Canvas means, you are coding in low level. In low level u have to do everything. working with View (ImageView) means, it is high level.In ImageView already defined in low level on canvas how to deal with AnimationDrawable.
Lars Blumberg's answer is correct but the documentation is incorrect; you also need to take into account this: animation start issue