Reputation: 2035
I'm trying to create an animation in which a LinearLayout
rises up (TranslateAnimation
) and the fragment within the LinearLayout
changes into another (fadein/fadeout).
I managed to get it to work perfectly, but the only problem is that the layout of the LinearLayout
stays at the same position (although the "fill" does rise and stay that way).
It results in that I can't click any view inside the fragment that is outside the previous position of the LinearLayout
.
How can I make the layout 'move up' to match the new position of the fill?
final int AmountToMove = -(desiredHeight - mLL.getHeight());
Animation animation = new TranslateAnimation(0, 0, 0, AmountToMove);
animation.setDuration(1000);
animation.setInterpolator(this,
android.R.anim.anticipate_overshoot_interpolator);
animation.setFillAfter(true);
if(CARD_STATE == 0)
mLL.startAnimation(animation);
animation.setAnimationListener(new TranslateAnimation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
LinearLayout.LayoutParams Lp = (LinearLayout.LayoutParams) mLL.getLayoutParams();
Lp.bottomMargin += AmountToMove;
mLL.setLayoutParams(Lp);
}
});
This too, did not work.
Upvotes: 0
Views: 1424
Reputation: 2035
In the end I managed to achieve my desired result, although not perfectly. Then I came up with another solution that does the job perfectly, but requires a sacrifice to be made hehe.
What I did was simply use LinearLayout.offsetTopAndBottom(int)
, where the parameter is the same amount of pixels you provided the TranslateAnimation
object.
Also note that for this to work you must set animation.setFillBefore(true)
and NOT .setFillAfter(true)
!
animation.setFillBefore(true);
animation.setAnimationListener(new TranslateAnimation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
mLL.offsetTopAndBottom(AmountToMove);
}
});
The problem with this solutions is that there is a flicker at the end of the animation when the view is actually being pushed up.
I'm not sure, but I also think it moves around weirdly when the keyboard opens, thus making this solution that that efficient. I suggest only using it when it satisfies your need in terms of the animation fluidity, and only on views without any EditText
views or any other input-requiring views.
I think that the thing is TranslateAnimation
moves pixels (or the fill of the view) and not the view itself, which is why I was personally confused at first.
My real solution (and also the second solution), however, was to switch to ObjectAnimator
instead of the regular Animation
object, and animate the translateY
property of the view.
It now works just as I wanted it to, no hiccups, no flickers, no problem with the keyboard, no problem editing views like EditText
.
Unfortunately, though, ObjectAnimator
is only supported in APIs 11+, but you can find a lower-api-compatible version of it on http://nineoldandroids.com/.
Personally, it got me wondering how many devices running API 8 are there anyways?
Apparently, as of writing this answer (July 10th, 2014), only 13.5 percent of the android devices worldwide run it, and this number only decreases with time.
Considering that, I decided to only support APIs 11+ in my app, because a lot of functionality that is critical to me was added in that version, and I do not see a reason to make the process of building the application any more difficult by trying to make the app compatible with API 8 using workarounds and a mix of libraries.
Saves a lot of time and head scratching!
Here is some code to demonstrate the usage of ObjectAnimator
for translation animations:
final int AmountToMove = -(desiredHeight - mLL.getHeight());
ObjectAnimator objAnim = ObjectAnimator.ofFloat(mLL, "translationY", AmountToMove);
objAnim.setDuration(1000);
objAnim.setInterpolator(new OvershootInterpolator());
objAnim.start();
Please note that is only my own personal opinion, which takes in mind my specific app and its target audience. Before making any rash decisions, I suggest weighing the pros against the cons of the switch, and deciding according to your own needs.
One last thing, please also like the other answer (written by Gil) as it helped me to come up with the first solution, and I appreciate that (I would've also marked it as the chosen answer but I wouldn't want to confuse or mislead other users who share the same kind of problem/confusion).
Upvotes: 0
Reputation: 16761
If you need the view to vanish after the animation is complete, then simply set the visibility as gone when the animation is finished:
animation.setAnimationListener(new TranslateAnimation.AnimationListener()
{
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationRepeat(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation)
{
mLL.setVisibility(View.GONE);
}
});
if you need to just make it move a bit, try adjusting its layout params (margin) once the animation is finished instead of just changing the visibility.
Upvotes: 1