I have a simple cardview topCard and want to translate it from the center of a layout to right side and back to the initial place.
Wrote some code using object animator:
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(topCard, "translationX", topCard.getWidth() + 150);
objectAnimator.setDuration(1500);
objectAnimator.start();
objectAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
ObjectAnimator translationX = ObjectAnimator.ofFloat(topCard, "translationX", - (topCard.getWidth() + 150));
translationX.setDuration(1500);
translationX.start();
So, my view correctly translates to the right side and the second animation move it not to the start place but to the (start place - (topCard.getWidth() + 150)).
How can I animate translating view to the right and back to the same position using 2 sequence animations?
Here is wrong result that i have
https://i.imgur.com/8SShfHL.gifv
You should try putting this in your onAnimationEnd instead:
#Override
public void onAnimationEnd(Animator animation) {
ObjectAnimator translationX = ObjectAnimator.ofFloat(topCard, "translationX",
topCard.getWidth() + 150, - (topCard.getWidth() + 150));
translationX.setDuration(1500);
translationX.start();
Notice that I added topCard.getWidth() + 150, making that the starting position of the topCard. According to the ObjectAnimator.ofFloat Android Docs:
Constructs and returns an ObjectAnimator that animates between float values. A single value implies that that value is the one being animated to. Two values imply starting and ending values.
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 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 am trying to learn a little bit about animations and so decided to get an ImageView to go across the screen from left to right, which I achieved with:
TranslateAnimation mAnimation = new TranslateAnimation(0, 180, 0, 0);
mAnimation.setDuration(1000);
mAnimation.setFillAfter(true);
mAnimation.setRepeatCount(-1);
mAnimation.setRepeatMode(Animation.REVERSE);
myImageView.setAnimation(mAnimation);
So, I decided to take on a new challenge. Once the image has gone from left to right, I wanted to try and get the image to return to the start position by arching back from right to left to its starting position (basically, a complete semi-circle). However, once the image has reached the end of the x-axis at position 180, I get stuck.
After reading about different methods for animation, I opted to try out ValueAnimator:
ValueAnimator animator = ValueAnimator.ofFloat(0, 1); // values from 0 to 1
animator.setDuration(1000); // 1 seconds duration from start to end position
animator.setRepeatCount(-1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) (animation.getAnimatedValue());
myImageView.setTranslationX((float)(180.0 * Math.sin(value*Math.PI)));
myImageView.setTranslationY((float)(80.0 * Math.cos(value*Math.PI)));
}
});
animator.addListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
// done
}
});
animator.start();
However, I am unable to get the positioning correct. I do have a semi-circle (good), however, it is moving the image like a backward C rather than a straight line left to right and then arching back to its starting position (bad).
I am not sure if I should be using AnimatorSet to link the left to right movement and the arching back movement together to create one whole animation...
Can anyone give me some guidance on how to achieve what I have described?
I'd like to translate view with ObjectAnimator twice, but the "X" position gets back to starting position after pressing the button again, how can i make it continue, and move further right in this case?
final ObjectAnimator animation = ObjectAnimator.ofFloat(button, "translationX", 100f);
animation.setDuration(2000);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
animation.start();
}
});
The reason your button jumps back to its starting position is covered in the documentation for the ofFloat() method:
A single value implies that that value is the one being animated to, in which case the start value will be derived from the property being animated and the target object when start() is called for the first time.
Because you're reusing the same ObjectAnimator instance every time, the translationX property is animated from its original (0) to the passed in argument (100) every time.
However, you can't just change it to create a new ObjectAnimator and have that solve everything. Let's say you changed your code to this:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final ObjectAnimator animation = ObjectAnimator.ofFloat(button, "translationX", 100f);
animation.setDuration(2000);
animation.start();
}
});
That would change what happens, but still not give you what you want. Now the button would slide from 0 to 100 the first time, but would remain stationary every time after that.
Why?
Because after the first animation, the translationX property is 100. So now you're animating between 100 and 100 (instead of 0 and 100)... which doesn't do anything.
The solution is to animate from the view's current translationX to the current value + 100. And to do that every time, instead of re-using the same ObjectAnimator over and over.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
float end = button.getTranslationX() + 100;
ObjectAnimator animation = ObjectAnimator.ofFloat(button, "translationX", end);
animation.setDuration(2000);
animation.start();
}
});
button.animate().translationX(button.translationX + 100f).setDuration(1000).start()
Works like a charm
Hello Stack community,
I want to change the position of text view.
I have tried several ways, but for all of them, the view position is set back to original position.
The ways I tried,
// 1. way
someText.setX(newPositionX);
someText.setY(newPositionY);
// 2.way
someText.x(newPositionX).y(newPositionY).setDuration(0).start();
// 3.way
someText.animate().x(newPositionX).y(newPositionY).setDuration(0).start();
//4.way
ObjectAnimator objectAnimatorX= ObjectAnimator.ofFloat(someText, "translationX", oldPositionX, newPositionX);
ObjectAnimator objectAnimatorY= ObjectAnimator.ofFloat(someText, "translationY", oldPositionY, newPositionY);
objectAnimatorX.setDuration(0);
objectAnimatorX.start();
objectAnimatorY.setDuration(0);
objectAnimatorY.start();
// 5.way
ObjectAnimator animX = ObjectAnimator.ofFloat(someText, "x", newPositionX);
ObjectAnimator animY = ObjectAnimator.ofFloat(someText, "y", newPositionY);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
For all these ways, it is reset to original place.
However when I use animate function in onTouch event eg. someText.animate().x(newPositionX).y(newPositionY).setDuration(0).start();
it does not set to original coordinate, the change is permanent. This what i want but I want to do this, without touch event, namely some other part of the code which uses some other events.
My questions are
Why the change is permanent when I use onTouch event while it is temporary when I dont use onTouch event?
How can I achieve to set Text position permanently?
Lastly my xml is like this for textView
`<TextView
android:id="#+id/latinBigTextView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
android:background="#drawable/border_text"
android:text="Initial text " />`
Somehow I have fixed. I have not still got the best results but it updates permanently. Most probably because of my calculations but for now it seems that the position update remains. I have used following code:
TranslateAnimation anim = new TranslateAnimation(0, deltaX, 0, deltaY);
anim.setDuration(0);
anim.setFillAfter(true);
anim.setFillEnabled(true);
anim.setAnimationListener(new Animation.AnimationListener()
{
#Override
public void onAnimationStart(Animation animation)
{
}
#Override
public void onAnimationEnd(Animation animation)
{
int l = newPosX;
int t = newPosY;
int r = SomeText.getWidth() + newPosX;
int b = SomeText.getHeight() + newPosY;
latinText.layout(l, t, r, b);
}
#Override
public void onAnimationRepeat(Animation animation)
{
}
});
latinText.startAnimation(anim);
Where SomeText is the textView which I want to move permanently and dynamically. DeltaX and DeltaY is the amount of pixel that I want to move.
(l, r, t, b) means (left, top, right, bottom) of the view.
I hope it helps other people who have faced the same problem.
However I have still no answer for my first question. If anyone knows and tells, I would be very appreciated.