Multiple ViewPropertyAnimators - android

Hope I am not duplicating a question here; I couldn't find one about multiple ViewPropertyAnimators. The goal is to have a view animate from y1 to y2 in 8 seconds. Fade in the first second, and then fade out on the last second.
Here is what I have Tried in my Activity's onCreate():
final View animatingView = findViewById(R.id.animateMe);
animatingView.post(new Runnable() {
#Override
public void run() {
//Translation
animatingView.setY(0);
animatingView.animate().translationY(800).setDuration(8000);
//Fading view in
animatingView.setAlpha(0f);
animatingView.animate().alpha(1f).setDuration(1000);
//Waiting 6 seconds and then fading the view back out
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
animatingView.animate().alpha(0f).setDuration(1000);
}
}, 6000);
}
});
However, the result is a translation from 0 to 800, and alpha from 0 to 1 all in one second. and then 6 seconds later the view fades out. It looks every time I call View.animate() it returns the same ViewPropertyAnimator. Is there a way I can have multiple of them? I was thinking about animating the view's alpha, nesting the view in a relative layout, and then animating the relative layouts translation. I would rather not go that route if I don't have to. Does anyone know of a better solution?

You can solve this by using ObjectAnimator instances directly, rather than using the .animate() abstraction.
ObjectAnimator translationY = ObjectAnimator.ofFloat(animatingView, "translationY", 0f, 800f);
translationY.setDuration(8000);
ObjectAnimator alpha1 = ObjectAnimator.ofFloat(animatingView, "alpha", 0f, 1f);
alpha1.setDuration(1000);
ObjectAnimator alpha2 = ObjectAnimator.ofFloat(animatingView, "alpha", 1f, 0f);
alpha2.setDuration(1000);
alpha2.setStartDelay(7000);
AnimatorSet set = new AnimatorSet();
set.playTogether(translationY, alpha1, alpha2);
set.start();

Related

How to start multiple ObjectAnimator on view simultaneously?

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

Reset view to original position after animation

I'm animating a view and I want to reset the view to the original position after animation ended.
This is what I have:
rl2 is a relativeLayout
rl2.animate().translationX(-60).translationY(117).setDuration(2000);
I tried setting this but its not working:
rl2.clearAnimation();
clearAnimation(); does not reset your animations, it just stops them and removes them from the animation queue. To undo your animations you need to actually undo them. So, for your code block you will need to call rl2.animate().translationX(0).translationY(0).setDuration(2000); to move the view back to its original position.
As #Chris Stillwell mentioned on his answer, But you can move View back to it's original position after translation animation by
rl2.animate().translationX(0).translationY(0);
I know this question was asked long time ago but someone may still look for answer.
I use the Animation class for this kind of thing; there is a setFillAfter method in this class, so you can set if you want the animation to apply its transformation after it ends.
Animation anim = new ScaleAnimation(
1f, 1f, // Start and end values for the X axis scaling
1f, 2f, // Start and end values for the Y axis scaling
Animation.RELATIVE_TO_SELF, 0f, // Pivot point of X scaling
Animation.RELATIVE_TO_SELF, 1f); // Pivot point of Y scaling
anim.setFillAfter(false); // no needed to keep the result of the animation
anim.setDuration(1000);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
gangsterImage.startAnimation(anim);
If you're going to remove view don't use animation.removeAllListeners(), the function cannot continue that's why you will see some error. If you want to disappear a view, use View.GONE
in Kotlin like this:
animation.doOnEnd {
binding.mainLayout.visibility = View.GONE}
But by this way you couldn't remove any animation! So it' better rest them to the initial position.
binding.tvM2.animate().translationX(0f).translationY(0f).rotation(0f)
just use anim.setFillAfter(false); to reset automatically after animation ends.

How to replicate sliding fragment 3d animation in Zazzle

I'm working on a project that calls for the navigation bar to be implemented in a fashion similar to how the Zazzle application does their navigation bar. Animations are not my expertise so I would like to get some ideas from the dev community on how such an animation can be implemented.
This is an image of the navigation drawer, notice how the previous fragment stays in view on the left.
Zazzle_navigation_Drawer
This is a screen shot of the nav transition when the menu button is pressed. It turns and tucks its self away in the right hand side of the screen and when the menu is dismissed it reverses that process.
Zazzle_nav_transition
I'm looking for a suggestion on how this might be implemented and maybe some resources I should look into using or information to learn in order to have a good shot of replicating this effect.
What I've done so far.
I have watched and took notes on the Sliding Animations DevBytes video.
So my strategy thus far is to make the navigation a fragment along with all my other screens and try and implement some sliding animations between them. I think this should give me the basic foundation.
Therefore I am more asking about how the animation would be constructed. I've never done animations before so I am asking for some help in the regards of how custom animations are implemented in android generally and a suggestion on how animation would be done in this case specifically
If anyone stumbles upon this...
I figured this out by using the sample project from the Android developer training website. I created an anim folder in res and adding xml set files with the Object animator tag. I didnt understand how to manipulate the values correctly to get the desired animation but after some poking around i realized the following
<objectAnimator
android:valueFrom=
android:valueTo=
android:propertyName="
android:interpolator=
android:duration= />
The valueFrom tag and the valueTo tag define the points the animation runs between and android fills in the rest. The property name is used to describe what kind of motion is being manipulated (translationX, translationY, rotationX, translationY, scaleX and scaleY). The interpolator sets the rate of change of the animation and finally duration specifies how long the animation should take.
Once the animation files are made the following code can be used to set the animations on the fragments during a transaction.
getFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.animator.exampleOut, R.animator.exampleIn,
R.animator.exampleOut, R.animator.exampleIn,
).add(R.id.container, new mFragment()).addToBackStack(null).commit();\
the first two parameters of setCustomAnimations() set the motion of the two fragments when the transaction is initiated and the last two parameters set the motion of the two fragments when the transaction is reversed, i.e., the back button is pressed.
This can be used to achieve the desired animation however I found that the outbound fragment would disappear from view for some reason. There fore I had to use AnimatorListener as follows:
Animator.AnimatorListener listener = new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator arg0) {
getFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.animator.exampleOut, 0,
0, R.animator.exampleIn
)
.add(R.id.container, new mFragment())
.addToBackStack(null)
.commit();
}
};
slideback(listener);
mHandler.post(new Runnable() {
#Override
public void run() {
invalidateOptionsMenu();
}
});
}
private void slideback(Animator.AnimatorListener listener) {
View movingFragmentView = cardFrontFragment.getView();
PropertyValuesHolder rotateY = PropertyValuesHolder.ofFloat("rotationY", 15f);
PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.8f);
PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.8f);
PropertyValuesHolder translateX = PropertyValuesHolder.ofFloat("translationX", 500f);
ObjectAnimator movingFragmentAnimator = ObjectAnimator.
ofPropertyValuesHolder(movingFragmentView, rotateY, scaleX, scaleY, translateX);
ObjectAnimator movingFragmentRotator = ObjectAnimator.
ofFloat(movingFragmentView, "rotationY",15f, 0f);
movingFragmentAnimator.setDuration(DURATION_TIME);
movingFragmentRotator.setStartDelay(DELAY_TIME);
AnimatorSet s = new AnimatorSet();
s.playTogether(movingFragmentAnimator, movingFragmentRotator);
s.addListener(listener);
s.start();
}
private void slideForward (Animator.AnimatorListener listener) {
View movingFragmentView = cardFrontFragment.getView();
PropertyValuesHolder rotateY = PropertyValuesHolder.ofFloat("rotationY", 15f);
PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
PropertyValuesHolder translateX = PropertyValuesHolder.ofFloat("translationX", 0f);
ObjectAnimator movingFragmentAnimator = ObjectAnimator.
ofPropertyValuesHolder(movingFragmentView, rotateY, scaleX, scaleY, translateX);
ObjectAnimator movingFragmentRotator = ObjectAnimator.
ofFloat(movingFragmentView, "rotationY",15f, 0f);
movingFragmentAnimator.setDuration(DURATION_TIME);
movingFragmentRotator.setStartDelay(DELAY_TIME);
movingFragmentRotator.setDuration(DURATION_TIME);
AnimatorSet s = new AnimatorSet();
s.playTogether(movingFragmentAnimator, movingFragmentRotator);
s.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mShowingBack = false;
}
});
s.start();
}
This allows you to set the properties for the outbound fragment dynamically during runtime and for some reason allows the fragment to remain in view.

How to execute TranslateAnimation sequentially without knowing how many translate you'll have to do (android)?

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();

Reverting animation done with AnimatorSet

I am creating an animation with AnimatorSet and when it ends I would like to leave the View where it was.
The code is something like this:
mLastAnimation = new AnimatorSet();
mLastAnimation.playTogether(
ObjectAnimator.ofFloat(mImageView, "scaleX", 1.5f, 1f),
ObjectAnimator.ofFloat(mImageView, "translationY", 40f, 0f));
mLastAnimation.setDuration(3000);
mLastAnimation.addListener(this);
mLastAnimation.start();
// The Activity implements the AnimatorListener interface
#Override
public void onAnimationEnd(Animator animator) {
// Undo the animation changes to the view.
}
EDIT:
I am using the new animation API so setFillAfter() will not work here.
If you are using nineoldandroids there is a function called reverse. You can set the duration to be 0 and call reverse to reverse the animation.
You have to set the properties of the View back to its original values.
For example if you translateY 40 pixels forward, you need to translateY 40 pixels backwards. This is because the actual properties of the View have changed during property animation, not just the way it is rendered.
http://developer.android.com/guide/topics/graphics/prop-animation.html#property-vs-view
While using ObjectAnimator you can simply set
android:repeatMode="reverse"
You can use this:
ObjectAnimator scaleX = ObjectAnimator.ofFloat(mImageView, "scaleX", 1.5f, 1f);
// here is the important part!
scaleX.setRepeatMode(ValueAnimator.REVERSE);
scaleX.setRepeatCount(1);
ObjectAnimator transl = ObjectAnimator.ofFloat(mImageView, "translationY", 40f, 0f));
// here is the important part!
transl.setRepeatMode(ValueAnimator.REVERSE);
transl.setRepeatCount(1);
mLastAnimation = new AnimatorSet();
mLastAnimation.playTogether(scaleX, transl);
// the rest is the same...

Categories

Resources