web-dev-qa-db-ja.com

Androidアクティビティ遷移を使用してフローティングアクションボタンをアニメーション化する方法は?

私は私のプロジェクトの1つにこのようなものを実装することを計画していますが、以下の概念は私には不明確であり、利用可能なそのようなチュートリアルもありません。これがどのように見えるかです ソースに行くにはここをクリック

enter image description here

私が理解したすべての参照から、彼らはここで2つのタイプのトランジションを使用して、ボタンを既存のボタンに移動し、別のボタンを爆発させました。だから私はいくつかの掘り下げを行い、githubでこれらの2つのライブラリを見つけました

マテリアルアニメーション (ボタンを移動するため)および 円形の表示 (ボタンが爆発したように見えるようにするため)

次へのより良い答えを見つけたらここに投稿してください

41
silverFoxA

あなたが探しているのは意味のある遷移だと思います。

Lollipop以前のデバイスでは、ActivityOptionsCompatヘルパーでこれを実現できます。

あなたを助けるかもしれないいくつかの有用なリンク:

5
Joen93

質問は古いですが、それでも面白いです。それが私がこれを実装した方法です:

enter image description here

最初に、遷移APIで「シーン」と呼ばれる2つのViewGroupsを作成する必要があります。最初のシーンには遷移前のビューが含まれ、2番目のシーンには遷移後のビューが含まれます。次に、最初のシーンを2番目のシーンに置き換えて、最初のシーンのビューが2番目のシーンに移動する方法、最初のシーンのビューが消える方法、2番目のシーンのビューを表示するTransitionを指定します。

enter image description here

この例では、「シーンルート」画面の白い領域からアニメーション化される唯一のビューであるため、fabボタンには問題があります。これが、シーンがフルスクリーンで、上部が青い「月曜日」ヘッダーの高さに等しい理由です。

ここのすべての遷移は、黄色の背景遷移を除いてデフォルトです。 2番目のシーンに黄色の背景ビューが表示され、円形のアニメーションが表示されます。そして、円形で表示され、崩壊アニメーションが表示されます。このようなデフォルトのアニメーションはありません。そのため、カスタムアニメーションを作成しました。

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

完全なコードはこちら:

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