Android - Animación de una vista topmargin / BottomMargin / etc en LinearLayout o RelativeLayout

StackOverflow https://stackoverflow.com/questions/2239442

Pregunta

Estoy tratando de crear un menú que se desliza hacia arriba desde la parte inferior. Se inicia con la opinión del menú apenas visible en la parte inferior de la pantalla, y luego hacer clic en él hace que se deslice hacia arriba. He intentado utilizar un TranslateAnimation, pero a pesar de los píxeles se mueven, las zonas más afectadas del menú están en la misma posición que antes. Así que creo que si puedo ajustar los márgenes del menú después de la animación es completa, esto va a lograr lo que quiero. Sin embargo, no puedo encontrar la manera de ajustar los márgenes.

He tratado de crear un objeto LinearLayout.LayoutMargins y después fijar sus márgenes y aplicarlo a la vista del menú (que es un LinearLayout), pero esto no funciona.

¿Alguna idea?

¿Fue útil?

Solución 2

Mi solución fue crear dos LinearLayouts, uno en le toca estado (ajustado a ido) y el otro en el estado de abajo del menú. Luego, cuando el usuario hace clic en el botón para deslizar el menú de arriba, lo llamo un TranslateAnimation mostrando la diapositiva menú desplegable. Pongo un oyente en la animación que hace que el estado hasta que sea visible y el estado presionado a estar fuera cuando termina la animación. Invertí esto para la acción "de cierre".

No es exactamente la forma en que había imaginado originalmente hacerlo, pero funcionó.

Otros consejos

Los siguientes trabajó para mí. En primer lugar decidir los márgenes inferiores (en salsas) para el menú estar hacia arriba (completamente visible) o hacia abajo (la mayor parte oculta).

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

Luego, en 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;
    }
});

Y aquí viene la salsa secreta; -)

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 uso dos funciones de utilidad:?

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!

Utilice la ViewPropertyAnimator:

if (view.getY() != margin) {
    view.animate().y(margin).setDuration(150).start();
}

Siento que este es un poco menos de un truco. Básicamente, se trata de hacer su propio animador. Por debajo de su configuración por sólo modificando topMargin en un RelativeLayout, pero no sería difícil generalizar.

import java.util.Calendar;

import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.RelativeLayout.LayoutParams;

public class MarginAnimation extends Thread {
    final String TAG = "MarginAnimation";
    long mStartTime;
    long mTotalTime;
    Interpolator mI;

    int mStartMargin;
    int mEndMargin;

    View mV;
    Activity mA;
    public MarginAnimation(Activity a, View v, 
            int startMargin, int endMargin, int totaltime,
            Interpolator i) {
        mV = v;
        mStartMargin = startMargin;
        mEndMargin = endMargin;
        mTotalTime = totaltime;
        mI = i;
        mA = a;
    }

    @Override
    public void run() {
        mStartTime = Calendar.getInstance().getTimeInMillis();
        while(!this.isInterrupted() && 
                Calendar.getInstance().getTimeInMillis() - mStartTime < mTotalTime) {

            mA.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(MarginAnimation.this.isInterrupted())
                        return;
                    long cur_time = Calendar.getInstance().getTimeInMillis();
                    float perc_done = 1.0f*(cur_time-mStartTime)/mTotalTime;

                    final int new_margin = (int)(1.0f*(mEndMargin-mStartMargin)*mI.getInterpolation(perc_done)) + mStartMargin;
                    LayoutParams p = (LayoutParams) mV.getLayoutParams();
                    Log.v(TAG, String.format("Setting Margin to %d", new_margin));
                    p.topMargin = new_margin;
                    mV.setLayoutParams(p);                  
                }
            });

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                return;
            }
        }
    }

}

Este post me ayudó a conseguir mi trabajo de animación. En mi caso, tengo una vista web de pantalla completa. En alguna acción del usuario, esta vista web se desliza hacia la derecha, alrededor del 70% y una nueva vista web surge de la izquierda y toma el espacio disponible. El resultado final, una nueva vista web cubre el 70% (eje x) y el viejo WebView el resto. La solución de Arne me ayudó muchísimo, establecer el margen a la antigua visión tan pronto como se realiza la animación. pseudo código:

       marginParams.leftMargin = 336; //(70% of 480px)

Pero me enfrentaba a un comportamiento extraño, supongo que mi viejo vista web (que ahora sólo ocupa un espacio 30%), fue volver a formatear su contenido, puede estar pensando que ahora está metida en un espacio más pequeño, en lugar de comportarse como si es sólo deslizado hacia la derecha. En otras palabras, tan pronto como me puse este margen, el diseño del HTML de la vista web cambió. Una vez más, no tenía ni idea de por qué y mi adivinar es que pensó su tamaño ventana padre cambió. Sobre la base de esa suposición, añadí una línea más de código:

      marginParams.rightMargin = -336; //(same amount, but negative margin!)

Y eso hizo el truco, no hay cambio de formato de los contenidos html y puedo interactuar con ambos webviews en paralelo.

Estoy publicar esto como un gran agradecimiento a Arne por la idea y también para obtener cualquiera de las entradas para el comportamiento que vi y mis supuestos para ello. De hecho, me gusta la solución final, tiene sentido lógico, pero puedo estar equivocado. . . cualquier pensamiento y de entrada sería muy apreciada. Muchas gracias.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top