Animación de la vista de un niño fuera del padre

Estoy intentando animar una visión fuera de su opinión del padre y cuando hago la visión del niño no puedo animar más allá de su padre. He resuelto esto usando el setClipChildren(false) y funcionó … Cuando la vista está animada. Cuando animo la vista hacia abajo, la imagen todavía está oculta.

Aquí está el código que funciona. Este código animará un botón de mosaico en la parte superior de la pantalla:

 private void setGameBoard(){ brickWall.setClipChildren(false); brickWall.setClipToPadding(false); //Build game board for(int ii = 0; ii < brickRows;ii++){ final int x = ii; //Build table rows row = new TableRow(this.getApplicationContext()); row.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 50)); row.setClipChildren(false); row.setClipToPadding(false); // row.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorAccent, null)); //Build table tiles for(int jj=0; jj < brickColumns; jj++){ final int y = jj; final Brick tile = new Brick(this); tile.setClipBounds(null); tile.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null)); //Set margins to create look of tic-tac-toe TableRow.LayoutParams lp = new TableRow.LayoutParams( 150, 75); lp.setMargins(0,0,0,0); //lp.weight = 1; tile.setLayoutParams(lp); tile.setWidth(3); tile.setHeight(10); tile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(tile.getHits() == 0){ tile.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorGreen, null)); tile.addHit(); } else if (tile.getHits() == 1){ tile.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorYellow, null)); tile.addHit(); }else if(tile.getHits() == 2){ brokenBricks++; float bottomOfScreen = getResources().getDisplayMetrics() .heightPixels; ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tile, "translationY", -2000); // 2 objectAnimator.setDuration(2000); tile.setHapticFeedbackEnabled(true); objectAnimator.start(); //tile.setVisibility(View.INVISIBLE); if(isRevealComplete()){ brickWall.setVisibility(View.INVISIBLE); } } } }); row.addView(tile); } brickWall.addView(row); } } 

Pero cuando ajusto la vista para ir a la parte inferior de la pantalla, la vista debajo de ella se "traga" y se oculta cuando llega a la parte inferior de la vista principal:

  private void setGameBoard(){ brickWall.setClipChildren(false); brickWall.setClipToPadding(false); //Build game board for(int ii = 0; ii < brickRows;ii++){ final int x = ii; //Build table rows row = new TableRow(this.getApplicationContext()); row.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 50)); row.setClipChildren(false); row.setClipToPadding(false); // row.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorAccent, null)); //Build table tiles for(int jj=0; jj < brickColumns; jj++){ final int y = jj; final Brick tile = new Brick(this); tile.setClipBounds(null); tile.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null)); //Set margins to create look of tic-tac-toe TableRow.LayoutParams lp = new TableRow.LayoutParams( 150, 75); lp.setMargins(0,0,0,0); //lp.weight = 1; tile.setLayoutParams(lp); tile.setWidth(3); tile.setHeight(10); tile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(tile.getHits() == 0){ tile.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorGreen, null)); tile.addHit(); } else if (tile.getHits() == 1){ tile.setBackgroundColor(ResourcesCompat.getColor(getResources(), R.color.colorYellow, null)); tile.addHit(); }else if(tile.getHits() == 2){ brokenBricks++; float bottomOfScreen = getResources().getDisplayMetrics() .heightPixels; ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tile, "translationY", 2000); objectAnimator.setDuration(2000); tile.setHapticFeedbackEnabled(true); objectAnimator.start(); //tile.setVisibility(View.INVISIBLE); if(isRevealComplete()){ brickWall.setVisibility(View.INVISIBLE); } } } }); row.addView(tile); } brickWall.addView(row); } } 

Así que mi pregunta es: ¿Cómo puedo animar una vista de niño fuera de una vista de padre debajo de la vista de niño?

ACTUALIZACIÓN 1

Si quito los azulejos debajo del azulejo que estoy tratando de dejar caer, entonces puedo ver el efecto deseado hasta que haya otro azulejo debajo de él, en cuyo punto el azulejo que cae irá "detrás" del azulejo que todavía está allí. Entonces, ¿cómo puedo obtener el azulejo de caída para moverse sobre los niños por debajo de él?

ACTUALIZACIÓN 2

Una cosa nueva que he notado es que si muevo el botón hacia la izquierda o hacia arriba, funciona bien; pero, si se mueve hacia abajo o hacia la derecha va detrás de las otras vistas. Esto me lleva a creer que los botones creados después de la baldosa actual tienen un efecto diferente.

Ok, por lo que en el enfoque alternativo que sugiero, usaría una clase de ayuda FlyOverView que toma una "foto" de cualquier vista, luego la anima a las coordenadas que desee. Una vez que la animación se está ejecutando, entonces puede ocultar / borrar la vista original, como lo que se mueve alrededor de la pantalla es sólo una imagen blitted sobre el lienzo. No tendrá que preocuparse por recortar otras vistas, etc.

Tendrá que declarar este FlyOverView en un contenedor externo de su sistema de ladrillos, y ese diseño tiene que cubrir todo el área donde desea que la animación sea visible. Por lo tanto, sugiero que utilice lo siguiente como contenedor de raíz, es sólo un FrameLayout donde dibujarás cosas sobre sus hijos.

 package whatever; public class GameRootLayout extends FrameLayout { // the currently-animating effect, if any private FlyOverView mFlyOverView; public GameRootLayout(Context context, AttributeSet attrs) { super(context,attrs); } @Override public void dispatchDraw(Canvas canvas) { // draw the children super.dispatchDraw(canvas); // draw our stuff if (mFlyOverView != null) { mFlyOverView.delegate_draw(canvas); } } /** * Starts a flyover animation for the specified view. * It will "fly" to the desired position with an alpha / translation / rotation effect * * @param viewToFly The view to fly * @param targetX The target X coordinate * @param targetY The target Y coordinate */ public void addFlyOver(View viewToFly, @Px int targetX, @Px int targetY) { if (mFlyOverView != null) mFlyOverView.cancel(); mFlyOverView = new FlyOverView(this, viewToFly, targetX, targetY, new FlyOverView.OnFlyOverFinishedListener() { @Override public void onFlyOverFinishedListener() { mFlyOverView = null; } }); } } 

que puede utilizar como contenedor

  <whatever.GameRootLayout android:id="@+id/gameRootLayout" android:layout_width="match_parent" android:layout_height="match_parent"> . . </whatever.GameRootLayout> 

Luego, el propio FlyOverView:

 package com.regaliz.gui.fx; import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.util.Log; import android.view.View; import android.support.annotation.Px; import android.view.animation.AccelerateDecelerateInterpolator; /** * Neat animation that captures a layer bitmap and "flies" it to the corner of the screen, used to create * an "added to playlist" effect or something like that. The method delegate_draw() must be called from the * parent view to update the animation * * @author rupps'2014 * license public domain, attribution appreciated */ @SuppressWarnings("unused") public class FlyOverView { public static final int DEFAULT_DURATION = 1000; private static final String TAG = "FlyOverView"; private static final boolean LOG_ON = false; private ObjectAnimator mFlyoverAnimation; private float mCurrentX, mCurrentY; private Matrix mMatrix = new Matrix(); private Bitmap mBitmap; private Paint mPaint = new Paint(); private View mParentView = null; private OnFlyOverFinishedListener mOnFlyOverFinishedListener; public interface OnFlyOverFinishedListener { void onFlyOverFinishedListener(); } /** * Creates the FlyOver effect * * @param parent Container View to invalidate. That view has to call this class' delegate_draw() in its dispatchDraw(). * @param viewToFly Target View to animate * @param finalX Final X coordinate * @param finalY Final Y coordinate */ public FlyOverView(View parent, View viewToFly, @Px int finalX, @Px int finalY, OnFlyOverFinishedListener listener) { setupFlyOver(parent, viewToFly, finalX, finalY, DEFAULT_DURATION, listener); } /** * Creates the FlyOver effect * * @param parent Container View to invalidate. That view has to call this class' delegate_draw() in its dispatchDraw(). * @param viewToFly Target View to animate * @param finalX Final X coordinate * @param finalY Final Y coordinate * @param duration Animation duration */ public FlyOverView(View parent, View viewToFly, @Px int finalX, @Px int finalY, int duration, OnFlyOverFinishedListener listener) { setupFlyOver(parent, viewToFly, finalX, finalY, duration, listener); } /** * cancels current animation from the outside */ public void cancel() { if (mFlyoverAnimation != null) mFlyoverAnimation.cancel(); } private void setupFlyOver(View parentContainer, View viewToFly, @Px int finalX, @Px int finalY, int duration, OnFlyOverFinishedListener listener) { int[] location = new int[2]; mParentView = parentContainer; mOnFlyOverFinishedListener = listener; viewToFly.getLocationInWindow(location); int sourceX = location[0], sourceY = location[1]; if (LOG_ON) Log.v(TAG, "FlyOverView, item " + viewToFly+", finals "+finalX+", "+finalY+", sources "+sourceX+", "+sourceY+ " duration "+duration); /* Animation definition table */ mFlyoverAnimation = ObjectAnimator.ofPropertyValuesHolder( this, PropertyValuesHolder.ofFloat("translationX", sourceX, finalX), PropertyValuesHolder.ofFloat("translationY", sourceY, finalY), PropertyValuesHolder.ofFloat("scaleAlpha", 1, 0.2f) // not to 0 so we see the end of the effect in other properties ); mFlyoverAnimation.setDuration(duration); mFlyoverAnimation.setRepeatCount(0); mFlyoverAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); mFlyoverAnimation.addListener(new SimpleAnimationListener() { @Override public void onAnimationEnd(Animator animation) { if (LOG_ON) Log.v(TAG, "FlyOver: End"); mParentView.invalidate(); if (mBitmap != null) mBitmap.recycle(); // just for safety mBitmap = null; mOnFlyOverFinishedListener.onFlyOverFinishedListener(); } }); // take snapshot of viewToFly viewToFly.setDrawingCacheEnabled(true); mBitmap = Bitmap.createBitmap(viewToFly.getDrawingCache()); viewToFly.setDrawingCacheEnabled(false); mFlyoverAnimation.start(); } // ANIMATOR setter public void setTranslationX(float position) { mCurrentX = position; } // ANIMATOR setter public void setTranslationY(float position) { mCurrentY = position; } // ANIMATOR setter // as this will be called in every iteration, we set here all parameters at once then call invalidate, // rather than separately public void setScaleAlpha(float position) { mPaint.setAlpha((int) (100 * position)); mMatrix.setScale(position, position); mMatrix.postRotate(360 * position); // asemos de to' mMatrix.postTranslate(mCurrentX, mCurrentY); mParentView.invalidate(); } /** * This has to be called from the root container's dispatchDraw() * in order to update the animation. */ public void delegate_draw(Canvas c) { if (LOG_ON) Log.v(TAG, "CX " + mCurrentX + ", CY " + mCurrentY); c.drawBitmap(mBitmap, mMatrix, mPaint); } private abstract class SimpleAnimationListener implements Animator.AnimatorListener { @Override public void onAnimationStart(Animator animation) {} @Override public void onAnimationRepeat(Animator animation) {} @Override public void onAnimationCancel(Animator animation) {} } } 

A continuación, cuando desea animar cualquier vista, sólo tiene que llamar a la función en el diseño de la raíz del juego:

 GameRootLayout rootLayout = (GameRootLayout)findViewById(...); . . rootLayout.addFlyOver(yourBrick, targetX, targetY); 

Este ejemplo también se aplica alfa y rotación a la vista, pero se puede sintonizar fácilmente a sus necesidades.

¡Espero que esto pueda inspirarle, si usted tiene cualquier pregunta siente libre de pedir!

Aunque la respuesta proporcionada por rupps puede resolver el problema, pero personalmente no usaría ese enfoque, porque:

  • Bitmap objeto de Bitmap en el hilo principal: debe esforzarse no hacer eso a menos que en una necesidad real.
  • Innecesariamente * agrega boilerplate a la base de código.

* Innecesariamente, porque el marco proporciona el API apropiado, que se menciona a continuación.

Por lo tanto, el problema que está tratando de resolver es animar una View fuera de los límites de su padre. Vamos a familiarizarse con ViewOverlay API:

Una superposición es una capa adicional que se sitúa encima de una vista (la "vista de host") que se dibuja después de todo el resto del contenido de esa vista (incluidos los niños, si la vista es un grupo de vistas). La interacción con la capa de superposición se realiza mediante la adición y extracción de elementos estirables.

Como lo mencionó Israel Ferrer Camacho en su charla "Smoke & Mirrors" :

ViewOverlay va a ser tu mejor amigo para siempre … en animaciones.

Como ejemplos de casos de uso puede ver esto :

introduzca la descripción de la imagen aquí Animación de iconos mediante la API de ViewOverlay . Esto se parece a la transición de elementos compartidos ?? Bueno, eso es porque la API de Transitions utiliza internamente ViewOverlay .

También un buen ejemplo de Dave Smith , que demuestra la diferencia entre usar ViewOverlay y Animator :

Para completar la respuesta, publicaré un fragmento de código del ejemplo de Dave Smith. El uso es tan simple como esto:

 container.getOverlay().add(button); 

El button se "superpuesta" encima del contenedor derecho en las coordenadas donde está en la jerarquía de vista. Ahora puede realizar animaciones en este button , pero el punto crucial es quitar la superposición una vez que no lo necesite:

 @Override public void onAnimationEnd(Animator arg0) { container.getOverlay().remove(button); } 
  • Actualizar el diseño con la animación
  • OnTouchListener en vista invisible
  • ¿Por qué no funciona setVisibility después de animar una vista?
  • Cómo ocultar la vista cuando se hace la animación en android?
  • Tween animación en una lona en una vista personalizada
  • Animación de Android - Flip
  • Creación de una presentación de diapositivas que desvanecen imágenes entre sí y transforman
  • Android - ¿Cómo crear un efecto de sacudidas como eliminar en iphone?
  • ProgressDialog Actividad de fondo Fade Out Animation
  • Androides ObjectAnimator.ofFloat no funciona correctamente
  • Loop AnimatorSet
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.