Quiero hacer un Animation para cuando un View obtiene la visibilidad de conjunto a GONE. En lugar de simplemente desaparezcan, el View debe ‘colapso’. He intentado esto con un ScaleAnimation pero luego la View es el colapso, pero el diseño sólo cambie el tamaño del espacio después (o antes) de la Animation se detiene (o comienza).

Cómo puedo hacer que el Animation de modo que, mientras la animación, el menor Views permanecerá directamente debajo del contenido, en lugar de tener un espacio en blanco?

  • He utilizado la misma técnica, como Andy que aquí se ha presentado, en mi ExpandAnimation: udinic.wordpress.com/2011/09/03/expanding-listview-items yo no uso una escala de animación, acabo de construir una nueva clase de Animación para que.
  • Esto era muy útil, mientras que yo estaba tratando de hacer esto. Gracias
  • Excelente Udinic .. realmente resuelto mi problema.. 🙂 gracias
  • Genial, tengo que adaptarme a mi problema, pero al final funciona. Para mí esta solución era mejor que la otra respuesta.
InformationsquelleAutor MrSnowflake | 2010-04-14

4 Comentarios

  1. 51

    No parece ser una manera fácil de hacer esto a través de la API, debido a que la animación sólo cambia la representación de la matriz de la vista, no el tamaño real. Pero podemos establecer un margen negativo para engañar a los LinearLayout en el pensamiento de que la vista es cada vez más pequeño.

    Así que me gustaría recomendar la creación de su propia clase de Animación, basada en ScaleAnimation, y la invalidación de la «applyTransformation» método para establecer nuevos márgenes y actualización del diseño. Como esto…

    public class Q2634073 extends Activity implements OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.q2634073);
            findViewById(R.id.item1).setOnClickListener(this);
        }
    
        @Override
        public void onClick(View view) {
            view.startAnimation(new MyScaler(1.0f, 1.0f, 1.0f, 0.0f, 500, view, true));
        }
    
        public class MyScaler extends ScaleAnimation {
    
            private View mView;
    
            private LayoutParams mLayoutParams;
    
            private int mMarginBottomFromY, mMarginBottomToY;
    
            private boolean mVanishAfter = false;
    
            public MyScaler(float fromX, float toX, float fromY, float toY, int duration, View view,
                    boolean vanishAfter) {
                super(fromX, toX, fromY, toY);
                setDuration(duration);
                mView = view;
                mVanishAfter = vanishAfter;
                mLayoutParams = (LayoutParams) view.getLayoutParams();
                int height = mView.getHeight();
                mMarginBottomFromY = (int) (height * fromY) + mLayoutParams.bottomMargin - height;
                mMarginBottomToY = (int) (0 - ((height * toY) + mLayoutParams.bottomMargin)) - height;
            }
    
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                super.applyTransformation(interpolatedTime, t);
                if (interpolatedTime < 1.0f) {
                    int newMarginBottom = mMarginBottomFromY
                            + (int) ((mMarginBottomToY - mMarginBottomFromY) * interpolatedTime);
                    mLayoutParams.setMargins(mLayoutParams.leftMargin, mLayoutParams.topMargin,
                        mLayoutParams.rightMargin, newMarginBottom);
                    mView.getParent().requestLayout();
                } else if (mVanishAfter) {
                    mView.setVisibility(View.GONE);
                }
            }
    
        }
    
    }

    La habitual advertencia se aplica: porque nos están dejando un método protegido (applyTransformation), esto no está garantizado para trabajar en futuras versiones de Android.

    • ¿Por qué diablos no me piensas de esto?! Gracias. También no entiendo la: «La habitual advertencia se aplica: porque nos están dejando un método protegido (applyTransformation), esto no está garantizado para trabajar en futuras versiones de Android.» – ¿Por qué habría de funciones protegidas difieren entre versiones de API? Aquellos que no están ocultos y son implementadas protegidos de modo que usted puede reemplazar (de lo contrario sería paquete de ámbito).
    • Usted está probablemente en lo cierto sobre el método protegido. Yo tiendo a ser más cautelosos acerca de cómo acceder a ellos de una API.
    • Al menos entonces usted está bastante seguro de que la API de las actualizaciones no se naufragio usted apps :).
    • Esto funcionó muy bien para mí, excepto que para conseguir «colapso» de trabajo (fromY=0.0 f, juguete=1.0 f), tuve que quitar el 0 - en el marginBottomToY de cálculo.
    • Sugeriría con el tipo genérico MarginLayoutParams en vez de echar a un determinado LayoutParam tipo.
    • gracias funcionando
    • Hay una manera fácil de hacer esto, vea mi respuesta
    • Supongamos que tengo que hacer conmutar animación, entonces ¿cómo podría hacerlo a la inversa. Por favor, consejos.

  2. 98

    Poner la vista en un diseño, si no lo es, y establecer android:animateLayoutChanges="true" de ese diseño.

    • Min API requerida es de 11 o más. No puede utilizar este método para bajar de versión.
    • hola Señor de la Vida 🙂
    • este es el más subestimado atributo de diseño…gracias!!
    • este sigue mostrando el espacio en blanco
  3. 7

    He utilizado la misma técnica como Andy aquí se ha presentado. Escribí mi propia clase de Animación para que, que animan al margen de su valor, haciendo que el efecto del elemento a desaparecer/a aparecer.
    Se parece a esto:

    public class ExpandAnimation extends Animation {
    
    //Initializations...
    
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
    
        if (interpolatedTime < 1.0f) {
    
            //Calculating the new bottom margin, and setting it
            mViewLayoutParams.bottomMargin = mMarginStart
                    + (int) ((mMarginEnd - mMarginStart) * interpolatedTime);
    
            //Invalidating the layout, making us seeing the changes we made
            mAnimatedView.requestLayout();
        }
    }
    }

    Tengo un ejemplo completo que funciona en mi blog
    http://udinic.wordpress.com/2011/09/03/expanding-listview-items/

  4. 2

    He utilizado la misma técnica como Andy aquí, y refinado por lo que puede ser utilizado para la expansión y contracción sin problemas, usando la técnica descrita aquí: https://stackoverflow.com/a/11426510/1317564

    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.view.animation.ScaleAnimation;
    import android.view.animation.Transformation;
    import android.widget.LinearLayout;
    
    class LinearLayoutVerticalScaleAnimation extends ScaleAnimation {
        private final LinearLayout view;
        private final LinearLayout.LayoutParams layoutParams;
    
        private final float beginY;
        private final float endY;
        private final int originalBottomMargin;
    
        private int expandedHeight;
        private boolean marginsInitialized = false;
        private int marginBottomBegin;
        private int marginBottomEnd;
    
        private ViewTreeObserver.OnPreDrawListener preDrawListener;
    
        LinearLayoutVerticalScaleAnimation(float beginY, float endY,
                LinearLayout linearLayout) {
            super(1f, 1f, beginY, endY);
    
            this.view = linearLayout;
            this.layoutParams = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();
    
            this.beginY = beginY;
            this.endY = endY;
            this.originalBottomMargin = layoutParams.bottomMargin;
    
            if (view.getHeight() != 0) {
                expandedHeight = view.getHeight();
                initializeMargins();
            }
        }
    
        private void initializeMargins() {
            final int beginHeight = (int) (expandedHeight * beginY);
            final int endHeight = (int) (expandedHeight * endY);
    
            marginBottomBegin = beginHeight + originalBottomMargin - expandedHeight;
            marginBottomEnd = endHeight + originalBottomMargin - expandedHeight;
            marginsInitialized = true;
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);     
    
            if (!marginsInitialized && preDrawListener == null) {                       
                //To avoid glitches, don't draw until we've initialized everything.
                preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {                    
                        if (view.getHeight() != 0) {
                            expandedHeight = view.getHeight();
                            initializeMargins();
                            adjustViewBounds(0f);
                            view.getViewTreeObserver().removeOnPreDrawListener(this);                               
                        }
    
                        return false;
                    }
                };
    
                view.getViewTreeObserver().addOnPreDrawListener(preDrawListener);                   
            }
    
            if (interpolatedTime < 1.0f && view.getVisibility() != View.VISIBLE) {          
                view.setVisibility(View.VISIBLE);           
            }
    
            if (marginsInitialized) {           
                if (interpolatedTime < 1.0f) {
                    adjustViewBounds(interpolatedTime);
                } else if (endY <= 0f && view.getVisibility() != View.GONE) {               
                    view.setVisibility(View.GONE);
                }
            }
        }
    
        private void adjustViewBounds(float interpolatedTime) {
            layoutParams.bottomMargin = 
                    marginBottomBegin + (int) ((marginBottomEnd - marginBottomBegin) * interpolatedTime);       
    
            view.getParent().requestLayout();
        }
    }
    • Es posible el uso de este primero colapso existente en un LinearLayout y, a continuación, expanda el mismo LinearLayout de nuevo después? Cuando trato de hacer esto, simplemente se derrumba y no se expanda de nuevo (probablemente debido a la altura de la vista ahora es 0 o algo así).
    • He encontrado que funciona de forma más fiable cuando el esquema lineal contiene más de una vista. Si éste contiene sólo una opinión, entonces no siempre se expanda.

Dejar respuesta

Please enter your comment!
Please enter your name here