如何使用 android 活动转换为浮动操作按钮设置动画?

Posted

技术标签:

【中文标题】如何使用 android 活动转换为浮动操作按钮设置动画?【英文标题】:How to animate floating action button using android activity transition? 【发布时间】:2015-07-02 23:55:44 【问题描述】:

我计划在我的一个项目中实现类似的东西,但我不清楚以下概念,也没有这样的教程,而且你不会经常看到这个。这是它的样子Click here to go to source

从我所了解的所有参考资料中,他们在这里使用了两种类型的过渡,一种将按钮移动到现有的某个位置,另一种使按钮爆炸。所以我做了一些挖掘并在github 中发现了这两个库,我认为通过这两个我们可以实现以下动画,这里是链接

Material Animations(移动按钮)和 Circular reveal(让按钮看起来像被炸了)

如果您对以下问题找到更好的答案,请在此处发布

【问题讨论】:

希望有人知道怎么做,因为google示例中充满了这种类型的过渡,但没有人用代码解释...... 您能否将链接发布到您遇到的示例? 查看此链接,这可能会对您有所帮助github.com/saulmm/Curved-Fab-Reveal-Example 编辑 ***.com/questions/30170786/… 我正在查看 Google 设计规范(必须如何成为 MatDesign)以及他关于动画必须如何的视频/gif 等等。真的是非常漂亮的过渡。从这里google.com/design/spec/what-is-material/… 开始,您将找到此规格和视频。 非常感谢,我检查了规格,但他们只是谈论它,但从未在那里找到任何概念或教程 【参考方案1】:

问题很老了,但它仍然很有趣。我就是这样实现的:

首先,您需要创建两个ViewGroups,在过渡 api 中称为“场景”。第一个场景包含转换前的视图,第二个场景包含转换后的视图。然后你应该用第二个场景替换第一个场景并提供Transition,它描述了从第一个场景到第二个场景的视图如何,以及第一个场景中的视图如何消失以及第二个场景中的视图如何出现。

在此示例中,fab 按钮存在困难,因为它是唯一一个在“场景根”屏幕的白色区域之外进行动画处理的视图。这就是为什么场景是全屏的,顶部边距等于蓝色“星期一”标题的高度。

这里的所有过渡都是默认的,除了黄色背景过渡。黄色的 背景视图出现在第二个场景中,带有圆形显示动画。并以圆形显示折叠动画消失。没有这样的默认动画,这就是我写自定义动画的原因:

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_
android:layout_
tools:context=".MainActivity">


    <android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_
    android:layout_
    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_
    android:layout_
    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_
        android:layout_
        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_
    android:layout_
    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_
android:layout_
android:clipChildren="false"
android:clipToPadding="false">

<LinearLayout
    android:id="@+id/slideLeftContainer"
    android:layout_
    android:layout_
    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_
    android:layout_
    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_
    android:layout_
    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_
android:layout_
android:clipChildren="false"
android:clipToPadding="false"
android:paddingTop="@dimen/header_height">

<View
    android:id="@+id/yellowBG"
    android:layout_
    android:layout_
    android:background="#FFEE4D" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_
    android:layout_
    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_
    android:layout_
    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_
    android:layout_
    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_
    android:layout_
    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_
    android:layout_
    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>

【讨论】:

不错的答案。谢谢。【参考方案2】:

我认为您正在寻找的是有意义的过渡

在棒棒糖之前的设备中,这可以通过ActivityOptionsCompat helper 来实现。

一些可能对您有所帮助的有用链接:

一个simple material design tutorial(带有源代码),它使用 ActivityOptionsCompat 用于过渡。 Android Developrs blog 上的转换示例(向下滚动 位)。 定义自定义动画在 Android 开发者培训 指导

【讨论】:

以上是关于如何使用 android 活动转换为浮动操作按钮设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

如何将浮动操作按钮锚定到App ToolBar,就像在指南图像中一样?

如何在浮动操作按钮中将图像设置为居中裁剪

关闭浮动操作按钮 Android

Android FloatingActionButton(浮动动作按钮的动画 ) 使用详情

如何在 android 上更改浮动操作按钮 (FAB) 的形状?

具有拖放功能的 Android 浮动操作按钮