enter code hereI want to implement a animation for items in a Recyclerview using ObjectAnimator. I have followed this tutorial
Here is my code for getting animations:
public static void animate(RecyclerView.ViewHolder holder, boolean direction)
{
AnimatorSet animatorSet=new AnimatorSet();
ObjectAnimator animator_Y=ObjectAnimator.ofFloat(holder.itemView,"TranslationY",direction==true ? 100 : -100,0);
animator_Y.setDuration(1000);
ObjectAnimator animator_X=ObjectAnimator.ofFloat(holder.itemView,"TranslationX",-20,20,0);
animator_X.setDuration(1000);
animatorSet.playTogether(animator_X,animator_Y);
animatorSet.start();
Log.e("animation","animation running");
}
I am calling this function from onBindViewHolder(). There is no animation from translationX and translationY. And I am sure that this method is being called everytime I scroll.
I want know that ObjectAnimator is used for Cardview or not. Thank you.`
This is my onBindViewHolder Method
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.textView.setText(data.get(position));
AnimationforAdapters.animate(holder,true);
}
Try the following code:
public static void animate(RecyclerView.ViewHolder holder, boolean direction) {
AnimatorSet animatorSet=new AnimatorSet();
ObjectAnimator animator_Y=ObjectAnimator.ofFloat(holder.itemView,"translationY",direction ? 100 : -100,0);
animator_Y.setDuration(1000);
ObjectAnimator animator_X=ObjectAnimator.ofFloat(holder.itemView,"translationX",-20,20,0);
animator_X.setDuration(1000);
animatorSet.playTogether(animator_X,animator_Y);
animatorSet.start();
Log.e("animation","animation running");
}
As mentioned in the android documentation for ObjectAnimator
This subclass of ValueAnimator provides support for animating properties on target objects. The constructors of this class take parameters to define the target object that will be animated as well as the name of the property that will be animated. Appropriate set/get functions are then determined internally and the animation will call these functions as necessary to animate the property.
So, the problem in your code was that the ObjectAnimator could not find properties TranslationX and TranslationY in your target object that can be animated.
use this its work for me :
public void slideAnimation(RecyclerView.ViewHolder holder, boolean animate) {
ObjectAnimator animatorY = ObjectAnimator.ofFloat(holder.itemView, "translationY", animate ? 40 : -40, 1f);
ObjectAnimator animatorX = ObjectAnimator.ofFloat(holder.itemView, "translationX", animate ? 40 : -40, 1f);
AnimatorSet set = new AnimatorSet();
set.playTogether(animatorX , animatorY);
set.setDuration(1000);
set.start();
}
try by maintaining reference of your row layout parent root xml tag into holder and use that instead of using holder.itemview.
Sorry guys, I have not enabled the animations in my device.Make Window animation scale,Transition animation scale,Animator duration scale to 1x inside the developer options.
Related
Here i am trying to move a view on a path with ObjectAnimator and also need to set one more scale animation on same view.
ObjectAnimator objectAnimator = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP)
{
objectAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
}
if (objectAnimator != null) {
objectAnimator.setDuration(2500);
objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator.start();
view.startAnimation(scaleRection);// this is not working because changing of x y position
need to start another Animation when objectAnimator.start();
also tried with listener
objectAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
view.startAnimation(scaleRection);
}
#Override
public void onAnimationEnd(Animator animation)
{
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
You can also use an AnimatorSet play together https://developer.android.com/reference/android/animation/AnimatorSet.html#playTogether and it's builder function https://developer.android.com/reference/android/animation/AnimatorSet.Builder
To play Two ObjectAnimator together
e.g.
AnimatorSet animationSet = new AnimatorSet();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view,"scaleY", 1f, 0f);
scaleY.setDuration(5000);
scaleY.setInterpolator(new AccelerateDecelerateInterpolator());
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view,"scaleX", 1f, 0f);
scaleX.setDuration(5000);
scaleX.setInterpolator(new AccelerateDecelerateInterpolator());
animationSet.playTogether(scaleX, scaleY);
animationSet.start();
I would suggest using ViewPropertyAnimator.
From the docs :
This class enables automatic and optimized animation of select
properties on View objects. If only one or two properties on a View
object are being animated, then using an ObjectAnimator is fine; the
property setters called by ObjectAnimator are well equipped to do the
right thing to set the property and invalidate the view appropriately.
But if several properties are animated simultaneously, or if you just
want a more convenient syntax to animate a specific property, then
ViewPropertyAnimator might be more well-suited to the task.
This class may provide better performance for several simultaneous
animations, because it will optimize invalidate calls to take place
only once for several properties instead of each animated property
independently causing its own invalidation. Also, the syntax of using
this class could be easier to use because the caller need only tell
the View object which property to animate, and the value to animate
either to or by, and this class handles the details of configuring the
underlying Animator class and starting it.
You can chain as many animations as you like at once in one line of code :
view.animate().translationX(...).translationY(...).scaleX(...).scaleY(...).setInterpolator(new AccelerateDecelerateInterpolator()).setDuration(2500);
if you need different values for your duration or similar, you can do it with two lines :
view.animate().translationX().setDuration(...) ...
view.animate().scaleX().setDuration(...) ...
There are also methods translationXBy() and scaleXBy() which might be more suitable for your case, and you can also set a listener etc. Check the docs for all available methods
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'd like to animate the backgroundTint value (and ideally the alpha value too) of a FloatingActionButton, so that the FAB background color continuously switches between two colors.
My noob approach would be to use a timer that calls a function that updates this property when it fires. I'm sure there's a better way of doing this?
I got this to work using ObjectAnimator as suggested by #MH. above, but I had to override the onAnimationUpdate() callback:
final ValueAnimator animator = ValueAnimator.ofInt(Color.rgb(0, 121, 107), Color.rgb(226, 143, 34));
animator.setDuration(2000L);
animator.setEvaluator(new ArgbEvaluator());
animator.setInterpolator(new DecelerateInterpolator(2));
animator.addUpdateListener(new ObjectAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
fab.setBackgroundTintList(ColorStateList.valueOf(animatedValue));
}
});
animator.start();
The question is simple but i tried to search a solution in other similar questions, and i couldn't.
I have a arraylist path containing objects of type Coordinata that is an object containing two float X and Y, that is a coordinate. In substance, it's a list of coordinate. I need my ImageView image to move on a map on my view doing several subsequential TranslateTrasformation between the coordinate contained in the list path.
This can be easily done in the case of a fixed number of translation, doing the first translate and attaching it a setAnimationListener which could catch the end of the first animation and start in that moment the second and so on. I tried to iterate the process on my list path, using a while cycle, for i cannot really know how many coordinate will be in the path when the animation will start.
The result is the animation go on for the first couple of coordinates and then jump executing the animation for the last two coordinate in the path, ignoring all that is among these.
What is going on? I'm messing up with objects?
List<Coordinata> path; // properly filled with coordinates
Coordinata coordTempStart;
Coordinata coordTempArrival;
ImageView image;
ListIterator<Coordinata> pathIterator = path.listIterator();
if(pathIterator.hasNext()){
coordTempStart = (Coordinata) pathIterator.next();
}
if(pathIterator.hasNext()){
coordTempArrival = (Coordinata) pathIterator.next();
animation = new TranslateAnimation(coordTempStart.getX(),
coordTempArrival.getX(),
coordTempStart.getY(),
coordTempArrival.getY());
animation.setDuration(3000);
image.startAnimation(animation);
}
while(pathIterator.hasNext()){
coordTempStart=coordTempArrival;
coordTempArrival = (Coordinata) pathIterator.next();
animation.setAnimationListener(new TranslateAnimation.AnimationListener(){
public void onAnimationStart(Animation arg0) {}
public void onAnimationRepeat(Animation arg0) {}
public void onAnimationEnd(Animation arg0) {
animation = new TranslateAnimation(coordTempStart.getX(),
coordTempArrival.getX(),
coordTempStart.getY(),
coordTempArrival.getY());
animation.setDuration(3000);
image.startAnimation(animation);
}
});
}
I suggest to use ObjectAnimator and AnimatorSet to animate views. Object animator is available only for api > 11 but you can use NineOldAndroid if you have to keep the compatibility.
your code will be something like this (in pseudocode):
...
AnimatorSet animatorSet = new AnimatorSet();
while(pathIterator.hasNext()){
...
//Set _your_delta_x_ and _your_delta_y_ from iterator
...
ObjectAnimator xTrasnlationObjectAnimator = ObjectAnimator.ofFloat(v, view_x, _your_delta_x_);
ObjectAnimator yTrasnlationObjectAnimator = ObjectAnimator.ofFloat(v, view_y, _your_delta_y_);
animatorSet.playSequentially(xTrasnlationObjectAnimator, yTrasnlationObjectAnimator);
}
...
animatorSet.start()
to set right parameters to object animator refer the official documentation http://developer.android.com/reference/android/animation/ObjectAnimator.html
Just for the sake of completeness, i publish the actual code used to solve the problem:
// in this list you can insert as many animations you want
List<Animator> animations = new ArrayList<Animator>();
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator xTrasnlationObjectAnimator = ObjectAnimator.ofFloat(image, View.TRANSLATION_X, (float)300);
xTrasnlationObjectAnimator.setRepeatCount(0);
ObjectAnimator yTrasnlationObjectAnimator = ObjectAnimator.ofFloat(image, View.TRANSLATION_Y, (float)300);
yTrasnlationObjectAnimator.setRepeatCount(0);
ObjectAnimator x2TrasnlationObjectAnimator = ObjectAnimator.ofFloat(image, View.TRANSLATION_X, (float)400);
x2TrasnlationObjectAnimator.setRepeatCount(0);
animations.add(xTrasnlationObjectAnimator);
animations.add(yTrasnlationObjectAnimator);
animations.add(x2TrasnlationObjectAnimator);
animatorSet.playSequentially(animations);
animatorSet.start();
I've been trying different approaches to get the expand/collapse animation with object animator but none of them so far worked.
I have used this solution and it works, but when I read the documentation it says it's more preferred to use animator to permanently animate objects rather than animation.
Problem with my code is that it always starts from top of the view, and yet I need to expand/collapse the view from bottom.
here is my code:
public boolean collapse( View view, int start, int end )
{
AnimatorSet set = new AnimatorSet();
ObjectAnimator a = ObjectAnimator.ofFloat( view, "translationY", start, end );
set.play( a );
set.setDuration( 3000L );
set.setInterpolator( new LinearInterpolator() );
set.addListener( new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd( Animator animation )
{
}
} );
set.start();
return true;
}
Trying using an ObjectAnimator.ofInt and use the property name of bottom. That will animate starting on the bottom of the view. TranslationY corresponds to the top of the view.