Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Animate a View's topMargin/bottomMargin/etc in LinearLayout or RelativeLayout

I am trying to create a menu that slides up from the bottom. It starts with the menu's view just visible at the bottom of the screen, and then clicking it causes it to slide up. I tried using a TranslateAnimation, but although the pixels move, the hit areas of the menu are in the same position as before. So I think that if I can adjust the menu's margins after the animation is complete, this will accomplish what I want. However, I can't figure out how to adjust the margins.

I've tried to create a LinearLayout.LayoutMargins object and then set its margins and apply it to the menu's view (which is a LinearLayout), but this doesn't work.

Any ideas?

like image 237
karnage Avatar asked Feb 10 '10 18:02

karnage


2 Answers

The following worked for me. First decide the bottom margins (in dips) for the menu being up (completely visible) or down (most of it hidden).

private static final int BOTTOM_MARGIN_UP = -50; // My menu view is a bit too tall.
private static final int BOTTOM_MARGIN_DOWN = -120;

Then, in onCreate():

menuLinearLayout = (LinearLayout)findViewById(R.id.menuLinearLayout);
setBottomMargin(menuLinearLayout, BOTTOM_MARGIN_DOWN);

upAnimation = makeAnimation(BOTTOM_MARGIN_DOWN, BOTTOM_MARGIN_UP);
downAnimation = makeAnimation(BOTTOM_MARGIN_UP, BOTTOM_MARGIN_DOWN);

Button toggleMenuButton = (Button)findViewById(R.id.toggleMenuButton);
toggleMenuButton.setOnTouchListener(new View.OnTouchListener()
{
    public boolean onTouch(View view, MotionEvent motionEvent)
    {
        if (motionEvent.getAction() != MotionEvent.ACTION_DOWN) return false;
        ViewGroup.MarginLayoutParams layoutParams =
            (ViewGroup.MarginLayoutParams)menuLinearLayout.getLayoutParams();
        boolean isUp = layoutParams.bottomMargin == dipsToPixels(BOTTOM_MARGIN_UP);
        menuLinearLayout.startAnimation(isUp ? downAnimation : upAnimation);
        return true;
    }
});

And here comes the secret sauce ;-)

private TranslateAnimation makeAnimation(final int fromMargin, final int toMargin)
{
    TranslateAnimation animation = 
        new TranslateAnimation(0, 0, 0, dipsToPixels(fromMargin - toMargin));
    animation.setDuration(250);
    animation.setAnimationListener(new Animation.AnimationListener()
    {
        public void onAnimationEnd(Animation animation)
        {
            // Cancel the animation to stop the menu from popping back.
            menuLinearLayout.clearAnimation();

            // Set the new bottom margin.
            setBottomMargin(menuLinearLayout, toMargin);
        }

        public void onAnimationStart(Animation animation) {}

        public void onAnimationRepeat(Animation animation) {}
    });
    return animation;
}

I use two utility functions:

private void setBottomMargin(View view, int bottomMarginInDips)
{
    ViewGroup.MarginLayoutParams layoutParams =    
        (ViewGroup.MarginLayoutParams)view.getLayoutParams();
    layoutParams.bottomMargin = dipsToPixels(bottomMarginInDips);
    view.requestLayout();
}

private int dipsToPixels(int dips)
{
    final float scale = getResources().getDisplayMetrics().density;
    return (int)(dips * scale + 0.5f);
}

Voila!

like image 123
Arne Evertsson Avatar answered Sep 28 '22 16:09

Arne Evertsson


My solution was to create two LinearLayouts, one in it's up state (set to gone) and the other in the menu's down state. Then when the user clicks on the button to slide the menu up, I call a TranslateAnimation showing the menu slide up. I put a listener on the animation that causes the up state to be visible and the down state to be gone when the animation finishes. I reversed this for the "closing" action.

Not exactly the way I had originally imagined doing it, but it worked.

like image 26
karnage Avatar answered Sep 28 '22 14:09

karnage