2010-02-10 19 views
11

Estoy tratando de crear un menú que se deslice desde la parte inferior. Comienza con la vista del menú apenas visible en la parte inferior de la pantalla, y luego haciendo clic en ella hace que se deslice hacia arriba. Intenté usar un TranslateAnimation, pero aunque los píxeles se mueven, las áreas afectadas del menú están en la misma posición que antes. Por lo tanto, creo que si puedo ajustar los márgenes del menú una vez completada la animación, esto logrará lo que quiero. Sin embargo, no puedo entender cómo ajustar los márgenes.Android - Animar vista de arribaMargin/bottomMargin/etc en LinearLayout o Relative Layout

He intentado crear un objeto LinearLayout.LayoutMargins y luego establecer sus márgenes y aplicarlo a la vista del menú (que es un LinearLayout), pero esto no funciona.

¿Alguna idea?

+0

No hay clase 'LinearLayout.LayoutMargins'. Supongo que te refieres a 'LinearLayout.LayoutParams'. Si pudiera publicar el código donde está ajustando los parámetros, eso podría ayudarnos a responder su pregunta. – CommonsWare

+0

Lo siento, tienes razón, quise decir 'LayoutParams'. Terminé usando otro método para lograr lo que quería. Construí dos vistas, una para el estado "menú abierto" y otra para el estado "menú cerrado". Luego usé una animación de traducción para deslizar el menú abierto hacia arriba y ocultar el menú cerrado, y viceversa. – karnage

Respuesta

3

Mi solución fue crear dos LinearLayouts, uno en su estado activo (configurado para desaparecer) y el otro en el estado inactivo del menú. Luego, cuando el usuario hace clic en el botón para deslizar el menú hacia arriba, llamo al TranslateAnimation mostrando el menú hacia arriba. Puse un oyente en la animación que hace que el estado de arriba sea visible y el estado de inactividad desaparezca cuando finaliza la animación. Invertí esto para la acción de "cierre".

No exactamente como lo había imaginado al hacerlo, pero funcionó.

+0

Parece como un hack ... ¡pero gracias! – speedplane

2

Siento que esto es un poco menos hackeo. Básicamente, está haciendo tu propio animador. Debajo está configurado para solo modificar topMargin en un RelativeLayout, pero no sería difícil generalizarlo.

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; 
      } 
     } 
    } 

} 
+0

No funcionó aquí, en Logcat puedo ver que establece el margen varias veces, pero solo el último tiene efectos en la vista. Intenté un mV.invalidate() después de mV.setLayoutParams (p) pero no funcionó, ¿alguna sugerencia? –

+0

Lo estoy llamando así: MarginAnimator ma = new MarginAnimator (EfeitosActivity.this, img2, lp.topMargin, 150, 500, nuevo AccelerateInterpolator()); ma.run(); –

+0

Tuve el mismo problema: utilizar la misma idea en una AsyncTask funcionó para mí. El código en la función de ejecución debe ejecutarse en doInBackground, y el código en el ejecutable uiThread debe ejecutarse en la función ProgressUpdate. –

21

Lo siguiente funcionó para mí. Primero decida los márgenes inferiores (en saltos) para que el menú esté arriba (completamente visible) o abajo (la mayor parte oculto).

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; 
} 

utilizo 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!

+0

Gracias Arne, ¡esto es increíble! – Tom

+0

Gran respuesta. Sin embargo, ¿es posible usar otro tipo de 'Animación' que modifique el margen en cada cuadro? Estoy haciendo una diapositiva de 'Fragmento' desde la parte inferior con su método y solo aparece al final de la animación, cuando el margen está en 'onAnimationEnd' (creo que no cambia de tamaño durante la animación). Sin embargo, funciona bien para deslizarlo. – Jukurrpa

+0

@Jukurrpa Lo siento, no tengo ni idea. Estoy haciendo la programación de Android en este momento. –

1

Esta publicación me ayudó a hacer funcionar mi animación. En mi caso, tengo una vista web de pantalla completa. En algunas acciones del usuario, esta vista web se desliza hacia la derecha, alrededor del 70% y una nueva vista web emerge de la izquierda y ocupa el espacio disponible. Resultado final: una nueva vista web cubre el 70% (eje x) y la vista web antigua el resto. La solución de Arne me ayudó inmensamente, configurando el margen de la vista anterior tan pronto como finaliza la animación. pseudo código:

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

Pero se enfrentó 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 simplemente se deslizara hacia la derecha. En otras palabras, tan pronto como establezco este margen, el diseño html de la vista web cambia. Una vez más, no tenía idea de por qué y mi conjetura se pensó que su tamaño de ventana padre ha cambiado.Sobre la base de ese supuesto, he añadido 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.

Lo estoy posteando como un gran agradecimiento a Arne por la idea y también para obtener cualquier información sobre el comportamiento que vi y mis suposiciones al respecto. De hecho, me gusta la solución final, tiene sentido lógico, pero puedo estar equivocado. . . cualquier pensamiento y aporte sería muy apreciado. Muchas gracias.

2

Uso del ViewPropertyAnimator:

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

¿Cuál es la gran solución para el hombre? gracias – bebosh

Cuestiones relacionadas