web-dev-qa-db-fra.com

Circulaire révèle la transition pour une nouvelle activité

Selon https://developer.Android.com/training/material/animations.html

La méthode ViewAnimationUtils.createCircularReveal() vous permet d'animer un cercle de découpage pour afficher ou masquer une vue.

Pour révéler une vue précédemment invisible à l'aide de cet effet:

// 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();

Ceci est destiné à révéler une vue. Comment puis-je utiliser ceci pour révéler de manière circulaire une activité entière, sans aucun élément partagé?

Plus précisément, j'aimerais que mon activité de recherche s'affiche de manière circulaire à partir du bouton d'action de recherche dans la barre d'outils.

67
Ishaan Garg

Après avoir cherché une solution sans résultat pendant une demi-journée, je suis venu avec une implémentation propre. J'utilise une activité transparente avec une mise en page racine correspondante. La disposition racine est une vue qui peut ensuite être révélée avec createCircularReveal().

Mon code ressemble à ceci:

Définition du thème dans 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>

Définition de l'activité dans AndroidManifest.xml

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

puis j'ai déclaré une présentation pour mon activité (j'ai choisi DrawerLayout pour disposer d'un NavDrawer. Chaque présentation devrait fonctionner ici.)

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

Important est le FrameLayout avec l'id root_layout. Cette vue sera révélée dans l'activité.

Finalement, j'ai implémenté CircularRevealActivity et écrasé 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);
                    } 
                }
            });
        }
    }
}

Il était important de mettre circularRevealActivity() dans un OnGlobalLayoutListener, car la vue doit être dessinée pour l'animation.

circularRevealActivity() ressemble à la proposition d'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();
}

Edit 1

La définition de R.anim.do_not_move A été ajoutée. Cependant, cela devrait également fonctionner sans cette ligne, si votre conception ne spécifie pas de transitions par défaut pour les activités. Faites le moi savoir

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>
83
Stefan Medack

Pour inverser l'animation CircularReveal, échangez les arguments startRadius et endRadius. De plus, vous devrez configurer AnimatorListeneret dans la méthode de rappel onAnimationEnd() vous pouvez appeler finishAfterTransition(). Ceci est pour quand vous appuyez sur le up navigation ou cliquez sur le back button.

7
toobsco42

Si vous souhaitez inverser la circulaire révélée à la fin de l'activité, utilisez la modification suivante de 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();
    }
}
7
jayasoo
6
TeeTracker

vous devez dessiner la vue circulaire, puis créer une animation.

Création de la vue circulaire:

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

Création de la classe d'animation pour définir le nouvel angle:

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

Mettez un cercle dans votre mise en page:

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

Et enfin pour commencer l'animation:

Circle circle = (Circle) findViewById(R.id.circle);

CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
animation.setDuration(1000);
circle.startAnimation(animation);
1
Mahesh Kumthekar