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
Related
I have an Activity with a toolbar (which is part of the SharedElements Activity entering animation) and below that toolbar are three ImageViews horizontally next to each other. In their XML implementation all three are set INVISIBLE.
What I'm trying to do is, to animate them sequentially "dropping" from behind the toolbar. My implemenation is this:
int delay = 500;
for (int y = 0; y < 3; y++) {
ObjectAnimator oa = ObjectAnimator.ofFloat(imageViews[y],
"translationY", -300, 0);
oa.setDuration(600);
oa.setStartDelay(delay);
oa.start();
imageViews[y].setVisibility(View.VISIBLE);
delay = delay+100;
}
}
As you can see, I'm iterating through the three ImageViews and start a animation for each one to go from a -300 X-position (which is behind the toolbar) to their normal position.
This animation works great - just as I want it to be, but the problem is, that right before all ImageViews are briefly flickering which I can't explain. I tried debugging, but while I'm going through the lines of that part my screen stays black. So I can't determine where/why the Views become visible.
Maybe you can help me to find my mistake.
Thank you, this is my working Code:
For all three ImageViews:
ObjectAnimator anim1Pin = ObjectAnimator.ofFloat(img_pinned, "translationY", -300, 0);
anim1Pin.setDuration(ANIMATON_DURATION);
anim1Pin.setStartDelay(300);
anim1Pin.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
img_pinned.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
And the AnimatorSet:
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(anim1Pin, anim2Alarm, anim3LED);
animatorSet.start();
Few things, first, the problem may be as simple as setting the visiblity state to GONE and then after animation starts, setting it to visible. However, I would also use AnimatorSet to play the animations together and add the delay rather than do it in a loop.
If you use AnimatorSet there is an onAnimationStart method in AnimationListener that you can use the set the visible to VISIBLE rather than do it how you have to ensure that they become visible at the right time.
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.
i want to animate button(ie; rotation, translation) then change the text of a button. unfortunately, it always first changes the text of the button then do the animation.
How can I achieve my goal?
Pls help me
my code is like this;
AnimationSet set = new AnimationSet(true);
Animation anim1 = new RotateAnimation(0, 360, 500, 750);
anim1.setDuration(3000);
anim1.setFillAfter(true);
set.addAnimation(anim1);
Animation anim2 = new RotateAnimation(0, 360, 1024, 824);
anim2.setDuration(3000);
anim2.setFillAfter(true);
set.addAnimation(anim2);
anim2.setStartOffset(3000);
first.clearAnimation();
set.setFillAfter(true);
first.startAnimation(set);
numbers[0]=min + (int)(Math.random() * ((max - min) + 1));
Your code starts the animation but is not blocking : once the animation is started, the program goes on.
You could try getting an handler and post the change text event at the right time :
Handler mHandler=new Handler();
Runnable lRunnable =new Runnable()
{
public void run()
{
//Your change text code
}
};
mHandler.postDelayed(lRunnable , 3000); // Or any other duration so you have the right effect
A better solution is to add an AnimationListener to the animation, or if you are on JB use the view property animators and the withEndAction() method. You should avoid the old animation framework if possible. It doesn't actually change the properties, it just draw the view with a transformation.
set.setAnimationListener(new AnimationListener() {
public void onAnimationEnd() {
// ...
}
public void onAnimationStart() {
}
public void onAnimationRepeat() {
}
}
But I recommend the view property animations if you can use them. They are much better to work with.
I have performed a Translation animation on button ,everything work as i excepted ,but only the problem is after the animation the button not responding to click event please correct me
Button b=(Button)findViewById(R.id.button1);
TranslateAnimation slide=new TranslateAnimation(0, 30, 0,-40);
slide.setDuration(500);
slide.setZAdjustment(TranslateAnimation.ZORDER_TOP);
slide.setFillAfter(true);
b.startAnimation(slide);
This will translate the object in y direction:
ObjectAnimator mover = ObjectAnimator.ofFloat(v, "translationY", 0, 400);
mover.start();
If you are handling animations at lower level API (below HoneyComb) your animation actually does not moves the button but only its images.Its click will be at same place where you have placed it in your layout.
I faced this issue and I did fix it just some second ago. So, I think that I should share my solution with you guys.
In animation xml file,I removed android:fillAfter="true" when keep android:fillEnabled="true".
Register Animation listener, then in onAnimationEnd() method, I call View#Layout() to change the position of the view.
int newLeft = (int) (layoutContent.getLeft() + layoutContent.getWidth() * 0.8);
layoutContent.layout(newLeft,
layoutContent.getTop(),
newLeft + layoutContent.getMeasuredWidth(),
layoutContent.getTop() + layoutContent.getMeasuredHeight());
In my case, what the animation do is that slides the layoutContent to leftside 80% of width.
It works fine. Hope this helps.
#Update: Today, you can use ObjectAnimator on android 3.0 +. If you are developing for android under 3.0, you can find it at support library v.4. ObjectAnimator is bester for animation.
#Update#2: You can use ViewPropertyAnimator on android api higher 12 version.
It provides better performance, and fix problem with click events. Example:
mButton.animate()
.setDuration(TIME)
.translationY(VALUE)
.start();
I could achieve what you wanted but you will have manage co-ordinates manually.
See if it works for you.
public class AnimationTestActivity extends Activity {
private Button mButton;
private LinearLayout.LayoutParams params;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(mClickListener);
params = (LayoutParams) mButton.getLayoutParams();
}
private android.view.View.OnClickListener mClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
TranslateAnimation animation = new TranslateAnimation(0, 0, 0, 400);
animation.setDuration(2000);
animation.setAnimationListener(mAnimationListener);
v.startAnimation(animation);
}
};
private AnimationListener mAnimationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
params.topMargin = params.topMargin + 400;
mButton.setLayoutParams(params);
}
};
}
The animation do not change the View actually Position. even if you setfillAfter(true), The position it can accept click event is the original position.
I found an easy solution define the button final position in layout and start the animation from some position ,ie specify the fromX or fromY instead of putting as zero
Try to use this:
b.layout(0, -40, b.getWidth(), b.getHeight());
Here is my scenario.
At first I do an animation set to my view (View.startAnimation(animationSet)) where animationSet consists of Translate + Rotate + Scale all at the same time. It works fine.
on that animationSet I have fillAfter(true).
After some time user click on a button and onClick I must start new ScaleAnimation on that same View. So if I do something like:
#Override
public void onClick(View v) {
ScaleAnimation scaleAnimation = new ScaleAnimation(mOldScaleFactor, mScaleFactor, mOldScaleFactor, mScaleFactor, mPivotX, mPivotY);
scaleAnimation.setDuration(ANIMATION_DURATION_MILIS);
scaleAnimation.setStartOffset(ANIMATION_OFFSET_MILIS);
scaleAnimation.setFillAfter(true);
v.startAnimation(scaleAnimation);
}
All the previous animation (Translate + Rotete + Scale) is forgotten.
How to start new animation from where old animation ends?
You could try to implement a listener and possible capture the information from when the previous animation left off, however I'm not sure you'll be able to query the animation for its state. Another option is to make sure the animation stops into a known state. That way you can know how you need to start the next animation.
public float param1;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
//load text view to add animation
ImageView image1 = (ImageView) findViewById(R.id.splash_imageView1);
Animation fade1 = AnimationUtils.loadAnimation(this, R.anim.fade_anim);
image1.startAnimation(fade1);
fade1.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation) {
//interrogate animation here
}