tools files componentes animations android animation material-design

android - componentes - material design files



Circular revela transiciĆ³n para nueva actividad (5)

Según https://developer.android.com/training/material/animations.html

El método ViewAnimationUtils.createCircularReveal() permite animar un círculo de recorte para revelar u ocultar una vista.

Para revelar una vista previamente invisible usando este efecto:

// previously invisible view View myView = findViewById(R.id.my_view); // get the center for the clipping circle int cx = (myView.getLeft() + myView.getRight()) / 2; int cy = (myView.getTop() + myView.getBottom()) / 2; // get the final radius for the clipping circle int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); // create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); // make the view visible and start the animation myView.setVisibility(View.VISIBLE); anim.start();

Esto está destinado a revelar una vista. ¿Cómo puedo usar esto para revelar circularmente una actividad completa, sin elementos compartidos?

Específicamente, me gustaría que mi searchActivity se revele circularmente desde el botón de acción de búsqueda en la barra de herramientas.



Después de buscar una solución durante medio día sin resultado, se me ocurrió una implementación propia. Estoy usando una actividad transparente con un diseño de raíz coincidente. El diseño raíz es una vista que luego se puede revelar con createCircularReveal() .

Mi código se ve así:

Definición del tema en styles.xml

<style name="Theme.Transparent" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowIsTranslucent">true</item> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item> </style>

Definición de actividad en AndroidManifest.xml

<activity android:name=".ui.CircularRevealActivity" android:theme="@style/Theme.Transparent" android:launchMode="singleTask" />

luego declare un diseño para mi actividad (elegí DrawerLayout, para poder tener un NavDrawer. Todos los diseños deberían funcionar aquí).

<android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <FrameLayout android:id="@+id/root_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/honey_melon" > <!-- Insert your actual layout here --> </FrameLayout> </android.support.v4.widget.DrawerLayout>

Importante es FrameLayout con el id root_layout . Esta vista se revelará en la actividad.

Finalmente implementé CircularRevealActivity y onCreate() :

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); overridePendingTransition(R.anim.do_not_move, R.anim.do_not_move); setContentView(R.layout.activity_reveal_circular); if (savedInstanceState == null) { rootLayout.setVisibility(View.INVISIBLE); ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver(); if (viewTreeObserver.isAlive()) { viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { circularRevealActivity(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); } } }); } } }

Era importante poner circularRevealActivity() en un OnGlobalLayoutListener , porque la vista debe dibujarse para la animación.

circularRevealActivity() parece a la propuesta de Ishaan:

private void circularRevealActivity() { int cx = rootLayout.getWidth() / 2; int cy = rootLayout.getHeight() / 2; float finalRadius = Math.max(rootLayout.getWidth(), rootLayout.getHeight()); // create the animator for this view (the start radius is zero) Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, 0, finalRadius); circularReveal.setDuration(1000); // make the view visible and start the animation rootLayout.setVisibility(View.VISIBLE); circularReveal.start(); }

Editar 1

Se agregó la definición de R.anim.do_not_move . Sin embargo, también debería funcionar sin esa línea, si su diseño no especifica las transiciones predeterminadas para las actividades. Házmelo saber

R.anim.do_not_move:

<set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromYDelta="0" android:toYDelta="0" android:duration="@android:integer/config_mediumAnimTime" /> </set>


Para invertir la animación CircularReveal intercambie los argumentos startRadius y endRadius . También deberá configurar un AnimatorListener y en el método de devolución de llamada onAnimationEnd() es donde puede llamar a finishAfterTransition() . Esto es para cuando presiona la up navigation o hace clic en el back button .


Si desea revertir la revelación circular al salir de la actividad, use la siguiente modificación para onBackPressed ().

@Override public void onBackPressed() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { int cx = rootLayout.getWidth(); int cy = 0; float finalRadius = Math.max(rootLayout.getWidth(), rootLayout.getHeight()); Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, finalRadius, 0); circularReveal.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { } @Override public void onAnimationEnd(Animator animator) { rootLayout.setVisibility(View.INVISIBLE); finish(); } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); circularReveal.setDuration(400); circularReveal.start(); }else{ super.onBackPressed(); } }


tienes que dibujar la vista circular, y luego debes crear una animación para ella.

Crear la vista circular:

public class Circle extends View { private static final int START_ANGLE_POINT = 90; private final Paint paint; private final RectF rect; private float angle; public Circle(Context context, AttributeSet attrs) { super(context, attrs); final int strokeWidth = 40; paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(strokeWidth); //Circle color paint.setColor(Color.RED); //size 200x200 example rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth); //Initial Angle (optional, it can be zero) angle = 120; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint); } public float getAngle() { return angle; } public void setAngle(float angle) { this.angle = angle; } }

Crear la clase de animación para establecer el nuevo ángulo:

public class CircleAngleAnimation extends Animation { private Circle circle; private float oldAngle; private float newAngle; public CircleAngleAnimation(Circle circle, int newAngle) { this.oldAngle = circle.getAngle(); this.newAngle = newAngle; this.circle = circle; } @Override protected void applyTransformation(float interpolatedTime, Transformation transformation) { float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime); circle.setAngle(angle); circle.requestLayout(); } }

Poner círculo en su diseño:

<com.package.Circle android:id="@+id/circle" android:layout_width="300dp" android:layout_height="300dp" />

Y finalmente comenzando la animación:

Circle circle = (Circle) findViewById(R.id.circle); CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240); animation.setDuration(1000); circle.startAnimation(animation);