web-dev-qa-db-fra.com

Comment animer un bouton d'action flottant à l'aide de Android transition d'activité?

Je prévois d'implémenter quelque chose comme ceci dans l'un de mes projets, mais le concept de ce qui suit ne m'est pas clair, il n'y a pas non plus de tel tutoriel disponible, de plus, vous ne le verrez pas très souvent. Voici à quoi ça ressemble Cliquez ici pour aller à la source

enter image description here

D'après toutes les références, ce que j'ai compris, c'est qu'ils ont utilisé deux types de transition ici, l'un pour déplacer le bouton jusqu'à un point existant et l'autre pour faire éclater le bouton. J'ai donc creusé un peu et trouvé ces deux bibliothèques dans github je pense qu'avec ces deux bibliothèques, nous pouvons réaliser l'animation suivante, voici les liens

animations matérielles (pour déplacer le bouton) et affichage circulaire (pour que le bouton ressemble à une explosion)

Si vous trouvez une meilleure réponse à la question suivante, postez ici s'il vous plaît

41
silverFoxA

Je pense que ce que vous recherchez, ce sont des transitions significatives .

Dans les appareils pré-Lollipop, ceci peut être réalisé avec ActivityOptionsCompat helper.

Quelques liens utiles qui pourraient vous aider:

5
Joen93

La question est ancienne, mais elle reste intéressante. Voici comment j'ai implémenté ceci:

enter image description here

Tout d’abord, vous devez créer deux ViewGroups qui, dans les api de transition, sont appelées "scènes". La première scène contient des vues avant la transition, la seconde contient des vues après la transition. Ensuite, vous devriez simplement remplacer la première scène par la deuxième et fournir Transition qui décrit comment les vues de la première scène vont à la deuxième scène, comment les vues de la première scène disparaissent et comment les vues de la deuxième scène apparaissent.

enter image description here

Dans cet exemple, le bouton fab contient des difficultés car il s'agit de la seule vue animée en dehors de la zone blanche de l'écran "scène racine". C’est pourquoi les scènes sont en plein écran avec une marge supérieure qui correspond à la hauteur de l’en-tête bleu "lundi".

Toutes les transitions sont par défaut sauf la transition avec un arrière-plan jaune. La vue de fond jaune apparaît dans la deuxième scène avec une animation à révélation circulaire. Et cela disparait avec une animation d'effondrement circulaire. Il n’ya pas d’animation par défaut comme celle-ci, c’est pourquoi j’en ai écrit une personnalisée:

import Android.animation.Animator;
import Android.animation.AnimatorListenerAdapter;
import Android.support.transition.TransitionValues;
import Android.support.transition.Visibility;
import Android.view.View;
import Android.view.ViewAnimationUtils;
import Android.view.ViewGroup;

public class CircularRevealTransition extends Visibility {

@Override
public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
    int startRadius = 0;
    int endRadius = (int) Math.hypot(view.getWidth(), view.getHeight());
    Animator reveal = ViewAnimationUtils.createCircularReveal(view, view.getWidth() / 2, view.getHeight() / 2, startRadius, endRadius);
    //make view invisible until animation actually starts
    view.setAlpha(0);
    reveal.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            view.setAlpha(1);
        }
    });
    return reveal;
}

@Override
public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
    int endRadius = 0;
    int startRadius = (int) Math.hypot(view.getWidth(), view.getHeight());
    Animator reveal = ViewAnimationUtils.createCircularReveal(view, view.getWidth() / 2, view.getHeight() / 2, startRadius, endRadius);
    return reveal;
}
}

Le code complet est ici:

import Android.os.Bundle;
import Android.support.annotation.NonNull;
import Android.support.design.widget.FloatingActionButton;
import Android.support.transition.ArcMotion;
import Android.support.transition.ChangeBounds;
import Android.support.transition.Fade;
import Android.support.transition.Scene;
import Android.support.transition.Slide;
import Android.support.transition.Transition;
import Android.support.transition.TransitionListenerAdapter;
import Android.support.transition.TransitionManager;
import Android.support.transition.TransitionSet;
import Android.support.v7.app.AppCompatActivity;
import Android.view.Gravity;
import Android.view.View;
import Android.view.ViewGroup;

public class MainActivity extends AppCompatActivity {

    private ViewGroup mSceneRoot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setSupportActionBar(findViewById(R.id.toolbar));
        mSceneRoot = findViewById(R.id.sceneRoot);
        //show scene1 without animation
        showScene1(false);
    }

    private void showScene1(boolean animated) {
        ViewGroup root = (ViewGroup) getLayoutInflater().inflate(R.layout.scene1, null);
        FloatingActionButton fab = root.findViewById(R.id.fab);
        fab.setOnClickListener(v -> {
            showScene2();
        });
        Scene scene = new Scene(mSceneRoot, root);
        Transition transition = animated ? getScene1Transition() : null;
        TransitionManager.go(scene, transition);
    }

    private void showScene2() {
        ViewGroup root = (ViewGroup) getLayoutInflater().inflate(R.layout.scene2, null);
        View btnBack = root.findViewById(R.id.btnCancel);
        btnBack.setOnClickListener(v -> {
            showScene1(true);
        });

        Scene scene = new Scene(mSceneRoot, root);
        Transition transition = getScene2Transition();
        TransitionManager.go(scene, transition);
    }

    private Transition getScene2Transition() {
        TransitionSet set = new TransitionSet();

        //fab changes position
        ChangeBounds changeTransform = new ChangeBounds();
        changeTransform.addListener(new TransitionListenerAdapter() {
            @Override
            public void onTransitionEnd(@NonNull Transition transition) {
                //hide fab button on the end of animation
                mSceneRoot.findViewById(R.id.fab).setVisibility(View.INVISIBLE);
            }
        });
        changeTransform.addTarget(R.id.fab);
        changeTransform.setDuration(300);
        //fab arc path
        ArcMotion arcMotion = new ArcMotion();
        arcMotion.setMaximumAngle(45);
        arcMotion.setMinimumHorizontalAngle(90);
        arcMotion.setMinimumVerticalAngle(0);
        changeTransform.setPathMotion(arcMotion);
        set.addTransition(changeTransform);

        //bg circular reveal animation starts
        CircularRevealTransition crt = new CircularRevealTransition();
        crt.addTarget(R.id.yellowBG);
        crt.setStartDelay(200);
        crt.setDuration(600);
        set.addTransition(crt);

        //buttons appear
        Fade fade = new Fade();
        fade.addTarget(R.id.btnBegin);
        fade.addTarget(R.id.btnCancel);
        fade.addTarget(R.id.text);
        fade.setStartDelay(600);
        set.addTransition(fade);

        //left buttons column slide to left
        Slide slide = new Slide(Gravity.LEFT);
        slide.addTarget(R.id.slideLeftContainer);
        set.addTransition(slide);
        //right buttons column slide to right
        Slide slide2 = new Slide(Gravity.RIGHT);
        slide2.addTarget(R.id.slideRightContainer);
        set.addTransition(slide2);
        return set;
    }

    private Transition getScene1Transition() {
        TransitionSet set = new TransitionSet();

        //buttons from scene2 fade out
        Fade fade = new Fade();
        fade.addTarget(R.id.btnBegin);
        fade.addTarget(R.id.btnCancel);
        fade.addTarget(R.id.text);
        set.addTransition(fade);

        //Circular Reveal collapse animation starts
        CircularRevealTransition crt = new CircularRevealTransition();
        crt.addTarget(R.id.yellowBG);
        crt.setDuration(600);
        set.addTransition(crt);

        //then fab button changes position
        ChangeBounds changeTransform = new ChangeBounds();
        changeTransform.addTarget(R.id.fab);
        changeTransform.setDuration(300);
        changeTransform.setStartDelay(500);
        //arc path
        ArcMotion arcMotion = new ArcMotion();
        arcMotion.setMaximumAngle(45);
        arcMotion.setMinimumHorizontalAngle(90);
        arcMotion.setMinimumVerticalAngle(0);
        changeTransform.setPathMotion(arcMotion);
        set.addTransition(changeTransform);

        //left buttons column slide in from left
        Slide slide = new Slide(Gravity.LEFT);
        slide.addTarget(R.id.slideLeftContainer);
        slide.setStartDelay(500);
        set.addTransition(slide);

        //right buttons column slide in from right
        Slide slide2 = new Slide(Gravity.RIGHT);
        slide2.addTarget(R.id.slideRightContainer);
        slide2.setStartDelay(500);
        set.addTransition(slide2);
        return set;
    }

}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<Android.support.constraint.ConstraintLayout 
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity">


    <Android.support.v7.widget.Toolbar
    Android:id="@+id/toolbar"
    Android:layout_width="match_parent"
    Android:layout_height="?attr/actionBarSize"
    Android:background="?attr/colorPrimary"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:titleTextColor="#fff" />

    <FrameLayout
    Android:id="@+id/topContainer"
    Android:layout_width="match_parent"
    Android:layout_height="@dimen/header_height"
    Android:background="#00BCD4"
    Android:orientation="vertical"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/toolbar">

        <TextView
        Android:layout_width="match_parent"
        Android:layout_height="36dp"
        Android:layout_gravity="bottom"
        Android:background="#9000"
        Android:gravity="center_vertical"
        Android:paddingLeft="8dp"
        Android:text="MONDAY"
        Android:textColor="#fff" />
    </FrameLayout>

    <FrameLayout
    Android:id="@+id/sceneRoot"
    Android:layout_width="match_parent"
    Android:layout_height="0dp"
    Android:clipChildren="false"
    Android:clipToPadding="false"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/toolbar" />

</Android.support.constraint.ConstraintLayout>

scene1.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/root"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:clipChildren="false"
Android:clipToPadding="false">

<LinearLayout
    Android:id="@+id/slideLeftContainer"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:layout_marginTop="@dimen/header_height"
    Android:orientation="vertical">

    <include layout="@layout/button" />
    <include layout="@layout/button" />
    <include layout="@layout/button" />
</LinearLayout>

<LinearLayout
    Android:id="@+id/slideRightContainer"
    Android:layout_width="wrap_content"
    Android:layout_height="match_parent"
    Android:layout_gravity="right"
    Android:layout_marginTop="@dimen/header_height"
    Android:orientation="vertical">

    <include layout="@layout/button" />
    <include layout="@layout/button" />
    <include layout="@layout/button" />
</LinearLayout>

<Android.support.design.widget.FloatingActionButton
    Android:id="@+id/fab"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_gravity="right"
    Android:layout_marginTop="@dimen/fab_margin_top"
    Android:layout_marginRight="@dimen/fab_margin"
    Android:clickable="true"
    Android:focusable="true"
    app:backgroundTint="#FFEE4D"
    app:srcCompat="@drawable/ic_add_black_24dp" />
</FrameLayout>

scene2.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/root"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:clipChildren="false"
Android:clipToPadding="false"
Android:paddingTop="@dimen/header_height">

<View
    Android:id="@+id/yellowBG"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="#FFEE4D" />

<Android.support.design.widget.FloatingActionButton
    Android:id="@+id/fab"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_gravity="center"
    Android:layout_margin="@dimen/fab_margin"
    app:backgroundTint="#FFEE4D"
    app:srcCompat="@drawable/ic_add_black_24dp" />

<Button
    Android:id="@+id/btnBegin"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_gravity="bottom|left"
    Android:layout_margin="@dimen/fab_margin"
    Android:padding="16dp"
    Android:text="BEGIN"
    Android:textSize="22sp" />

<TextView
    Android:id="@+id/text"
    Android:layout_width="@dimen/header_height"
    Android:layout_height="wrap_content"
    Android:layout_gravity="center"
    Android:gravity="center"
    Android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt"
    Android:textSize="22sp" />

<Button
    Android:id="@+id/btnCancel"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_gravity="bottom|right"
    Android:layout_margin="@dimen/fab_margin"
    Android:backgroundTint="#FF5151"
    Android:padding="16dp"
    Android:text="CANCEL"
    Android:textSize="22sp" />

</FrameLayout>

button.xml:

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:layout_margin="16dp"
    Android:padding="24dp"
    Android:text="6:30"
    Android:textSize="24sp" />

values.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">TestTransition</string>

    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <dimen name="fab_margin">16dp</dimen>
    <dimen name="header_height">200dp</dimen>
    <dimen name="fab_margin_top">132dp</dimen>
</resources>
5
ashakirov