I was trying to find documentation about how to create icon animation of FAB's (of the Design support library), after searching a while i couldn't find any information about it and the AnimationDrawable reference in android developers doesn't work for FAB's even if the class is a child of ImageView.
but manage to get a workaround that works just fine.
The technic I used is similar to the one exposed on the DrawableAnimation documentation, and using the Property Animation API doc.
First I use the ValueAnimator class, and an int array containing the ids of the drawables that you're going to use in your animation.
final int[] ids = {R.drawable.main_button_1,R.drawable.main_button_2,R.drawable.main_button_3,R.drawable.main_button_4,R.drawable.main_button_5,R.drawable.main_button_6, R.drawable.main_button_7};
fab = (FloatingActionButton) findViewById(R.id.yourFabID);
valueAnimator = ValueAnimator.ofInt(0, ids.length - 1).setDuration(yourAnimationTime);
valueAnimator.setInterpolator( new LinearInterpolator() /*your TimeInterpolator*/ );
Then set up an AnimationUpdateListener, and define the change in icon behavior with the method FloatinActionButton.setImageDrawable(Drawable yourDrawable).
But the ValueAnimator updates by default every available frame (depending on the load in hardware), but we don't need to redraw the icon if it has already been drawn, so that is why I use the variable "i"; so each icon is drawn only once. (the timing depends on the interpolator you define)
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int i = -1;
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
if(i!=animatedValue) {
fab.setImageDrawable(getResources().getDrawable(ids[animatedValue]));
i = animatedValue;
}
}
});
This implementation allows you to play the animation backward with the method ValueAnimator.reverse();
I know is not a pro solution but it's the only one I've figured out to work on all API's supporting the PropertyAnimation. Please, if you know a better solution post it here, if not I hope this post is helpful
You can achieve FAB's src drawable animation quite similarly to other views that use background for AnimationDrawable.
For general views' background drawable animation, see Use AnimationDrawable.
However, you cannot call getBackground() to get FAB's src.
Instead, use getDrawable().
Example:
FloatingActionButton loginButton = findViewById(R.id.loginButton);
loginAnimation = (AnimationDrawable) loginButton.getDrawable();
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
loginAnimation.start();
}
});
Related
I have custom ImageView which should animate its content after loading from solid background color to image with setColorFilter:
private void _animate() {
int bgColor= ContextCompat.getColor(getContext(), R.color.iconPlaceholderBg);
int transparent=ContextCompat.getColor(getContext(),android.R.color.transparent);
ValueAnimator bgAnim= ValueAnimator.ofObject(new ArgbEvaluator(),bgColor,transparent);
bgAnim.setDuration(5000);
//bgAnim.setInterpolator(new DecelerateInterpolator());
bgAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
//Log.d("anim",animation.getAnimatedFraction()+"")
//Image.this.clearColorFilter();
Image.this.setColorFilter((int)animation.getAnimatedValue());
}
});
bgAnim.start();
}
Animation itself runs as expexted (5 seconds long).However content appears immediately in the final position(without color transformation).I've tried different PorterDuff.Mode modes but looks like none of them do things right.Are there any workarounds to get desired effect?
The problem was with my background color which has tranparency.For some reason setColorFilter works not exactly as you expect with trasparent colors.I've managed to get desired behaviour with following workaround:
Image.this.getDrawable().setAlpha((int) (animation.getAnimatedFraction()*255));
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.
I am trying to expand and shrink the width of container with animation.
I am doing both of those with ValueAnimator and both of those are working fine separately.
The expand animation will be perform when the user scroll up the cards and shrink animation will be perform when the user scroll down the cards.
Because all of those cards are in ScrollView container, the user can scroll up / down whenever they want even though the expanding / shrinking Animation is not finished.
To be more clear, it looks like the shrink animation is being triggered when the cards are still expanding. Below is my code for expanding / shrinking.
private void animateResizeWidth(final View vcLogin, int widthReduce){
ValueAnimator anim;
if(widthReduce == 0){
anim = ValueAnimator.ofInt((ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH) - ScreenUtils.getObjInstance().getPixelFromDPI(widthReduce)), ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH));
}else{
anim = ValueAnimator.ofInt(ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH), (ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH) - ScreenUtils.getObjInstance().getPixelFromDPI(widthReduce)));
}
final RelativeLayout.LayoutParams finalLp2 = new RelativeLayout.LayoutParams(vcLogin.getLayoutParams());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
finalLp2.width = val;
finalLp2.addRule(RelativeLayout.CENTER_HORIZONTAL);
vcLogin.setLayoutParams(finalLp2);
vcLogin.invalidate();
}
});
anim.setDuration(400);
anim.start();
}
So, whenever that happen, the size of the cards are being set to regular size and the resize animation won't trigger anymore (Need to restart the Host Activity).
I have tried the answer from here. But, it is not helping me.
My Questions are 1: Is there any other Animation Mechanism that
I can use for width animation except ValueAnimator ? I have checked
ObjectAnimator but, not supporting. Ref 2: Is that thread
issue ? 3: I should not be blocking user from scrolling down
just because my expanding animation is not finished. So, what I haven
in mind is if the user scroll down, I will just terminate any of my
pending animations. Is there any thread-related issue that I need to consider for this approach ? (I have written a Custom
ScrollView to detect those scroll-related events.)
I think I am missing a few thread-safe logics in above animation implementation.
Thanks
I want to create skew animation for a View in android.
So, I have rectangular view (this is normal/start state), at the end it should looks like this:
I can do such a thing with android.view.animation package using Transformation of TYPE_MATRIX. So I can create Matrix and use preSkew method, apply this Matrix to my custom animation and then start this animation on a view. So this is OK.
BUT
The problem is I want to do this with ObjectAnimator.
Because using android.view.animation package is not recommended to use.
But I can't get the solution for this problem with ObjectAnimator class.
If I have ImageView, I can use method setImageMatrix for ObjectAnimator (and also create custom MatrixEvaluator to evaluate corresponding matrices for each factor),
but I want to get solution for this problem with a View class, not for some subclass of it.
And the main reason is, that TextView, for example, doesn't have public method like setMatrix, and I want to get the solution for TextView too. So get the solution for base View class is the main desire.
There is another solution: create custom, for example, SkewTextView, in which onDraw method we use canvas.skew method.
But this is worse solution even than using android.view.animation package, because you need to create wrappers for any View subclass you want to skew.
So, I don't know, how I can skew View with a ObjectAnimator (as View class doesn't have public methods like setSkew or setMatrix).
How would you solve this problem?
Have you any idea of how to solve this problem?
Is there a solution for this problem with ObjectAnimator?
Any help (or even thoughts) is greatly appreciated
Thanks
Well without subclassing this might be a bit tricky. My main idea is to use TimeAnimator, which will provide you time callbacks in conjunction with Camera (which can use Matrix transformations). Or you can use TimeAnimator and make a Bitmap from the View you want to skew, make the original View invisible, and draw the Bitmap on each TimeAnimator step applying a Matrix to it. But I'm not sure if this is the optimal way to do that, since you will have to create a new Bitmap on each frame
EDIT: No, Camera approach is not the way to do that as it is stated in comments below
I created a skew animation using Android Property Animation APIs in my project (GitHub Link).
What I did:
Created a custom view (SkewView) and added a SKEW_X property to it.
public class SkewView extends ImageView {
private static final String TAG = "SkewView";
public static final Property SKEW_X
= new FloatProperty("skewX") {
#Override
public void setValue(SkewView object, float value) {
object.setSkewX(value);
}
#Override
public Float get(SkewView object) {
return object.getSkewX();
}
};
private float mSkewX;
// ...
public float getSkewX() {
return mSkewX;
}
public void setSkewX(float skewX) {
mSkewX = skewX;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
if (mSkewX != 0) {
canvas.skew((float) (mSkewX * Math.PI / 180.0f), 0);
}
super.onDraw(canvas);
}
}
Used ObjectAnimator to animate this property.
ObjectAnimator skewAnimator = ObjectAnimator.ofFloat(mTarget, SkewView.SKEW_X, 30);
I have an imageview with a default image. Now when I try to click it, I want it to animate that displays 4 frames of images. How could I accomplish this, I tried a simpler approach (more of a dumb approach) by changing the imageresource 4 times, as expected the image changes so fast that the animating image effect is not visible. Any ideas?
I tried this approach:
Gem = (ImageView)v;
Gem.setImageResource(com.example.gems.R.drawable.bd1);
Gem.postDelayed(new Runnable() {
public void run() {
Gem.setImageResource(com.example.gems.R.drawable.bd2);
Gem.postDelayed(new Runnable() {
public void run() {
Gem.setImageResource(com.example.gems.R.drawable.bd3);
Gem.postDelayed(new Runnable() {
public void run() {
Gem.setImageResource(com.example.gems.R.drawable.bd4);
Gem.postDelayed(new Runnable() {
public void run() {
}
}, 500);
}
}, 500);
}
}, 500);
}
}, 500);
It worked, but is there a better way to this without coding too much lines? I have 25 kinds of images and each image has 4 frames.
EDIT:
I tried using xml transition files:
Java file:
Resources res = this.getResources();
Gem = (ImageView)v;
TransitionDrawable transition;
transition = (TransitionDrawable)
res.getDrawable(R.drawable.blue_diamond_animation);
Gem.setImageDrawable(transition);
transition.startTransition(3000);
xml file:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/bd1"></item>
<item android:drawable="#drawable/bd2"></item>
<item android:drawable="#drawable/bd3"></item>
<item android:drawable="#drawable/bd4"></item>
<item android:drawable="#drawable/invi"></item>
</transition>
This seems to work, but I don't want to draw this images in a transition. I want to change the background in a transition. I tried changing this android:drawable to android:drawable but it doesn't work.
It turns out that there is an exact class for this: AnimationDrawable
Basically, just add frames with the other pictures to use in the animation to the AnimationDrawable object and specify how long they should display using addFrame(Drawable frame, int duration)
Then set the ImageView to display whatever image it should start with and set the background to the AnimationDrawable you just made using setBackgroundDrawable(Animation)
Lastly, start the animation in the onClick listener
EDIT: FOR EXAMPLE
AnimationDrawable ad = new AnimationDrawable();
ad.addFrame(getResources().getDrawable(R.drawable.image1), 100);
ad.addFrame(getResources().getDrawable(R.drawable.image2), 500);
ad.addFrame(getResources().getDrawable(R.drawable.image3), 300);
ImageView iv = (ImageView) findViewById(R.id.img);
iv.setBackgroundDrawable(animation);
And then in your onClick listener, just call ad.start
It depends on what you are trying to accomplish. You have not given enough info to go on
The viewproperty animator is really the easiest thing to use have a look. It can also be used with older API's using nineoldandroids jar (google it)
http://developer.android.com/reference/android/view/ViewPropertyAnimator.html
The ObjectAnimator and ValueAnimator are also available similar and slightly more difficult to implement
http://developer.android.com/reference/android/animation/ObjectAnimator.html
http://developer.android.com/reference/android/animation/ValueAnimator.html
Have a look at the APIdemos in the sample packs there are a few examples mainly using the ValueAnimator.
http://developer.android.com/tools/samples/index.html
There are also Sprites to consider but it is basically a bitmap , you can user the timer obect to choreograph