动画一个Android浮动动作按钮
自材质设计引入以来,浮动动作按钮(FAB)已经成为实现最简单的组件之一,成为设计师和开发人员的快速和基本最爱。
在本教程中,我将向您展示如何使您的应用程序FAB互动,以及如何制作自己的动画。但让我们从简单的开始,添加浮动动作按钮到Android项目。
浮动动作按钮在布局文件中看起来像这样,如果创建一个Android Studio项目使用空白的活动:
<android.support.design.widget.FloatingActionButtonandroid:id="@ + id /工厂"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="底|结束"android:layout_margin="@dimen / fab_margin"android:src="@android:可拉的/ ic_menu_help"/>
浮动动作按钮
浮动操作按钮有两种大小。默认值是56dp,最小值是40dp。关于使用FAB的设计原则的进一步讨论,我建议您阅读谷歌的官方指南.
在最近的Android应用中,FAB会对元素列表的滚动做出反应,在我看来,在滚动时应该隐藏FAB。我的意思是:
为了显示这个动画,我创建了一个recyclerView
这样FAB就可以对滚动做出反应。
有很多库可以在1或2行代码中帮助实现这一目标,但对于那些好奇的人来说,这里有一个例子:
公共类FAB_Hide_on_Scroll扩展FloatingActionButton.行为{公共FAB_Hide_on_Scroll(上下文上下文,AttributeSetattrs){超级();}@Override公共无效onNestedScroll(CoordinatorLayoutcoordinatorLayout,FloatingActionButton孩子,视图目标,intdxConsumed,intdyConsumed,intdxUnconsumed,intdyUnconsumed){超级.onNestedScroll(coordinatorLayout,孩子,目标,dxConsumed,dyConsumed,dxUnconsumed,dyUnconsumed);//child ->浮动动作按钮如果(孩子.getVisibility()= =视图.可见& &dyConsumed>0){孩子.隐藏();}其他的如果(孩子.getVisibility()= =视图.走了& &dyConsumed<0){孩子.显示();}}@Override公共布尔onStartNestedScroll(CoordinatorLayoutcoordinatorLayout,FloatingActionButton孩子,视图directTargetChild,视图目标,intnestedScrollAxes){返回nestedScrollAxes= =ViewCompat.SCROLL_AXIS_VERTICAL;}}
我用的是FloatingActionButton.Behavior ()
类,根据官方文件,其主要功能是移动FloatingActionButton
视图,以便显示任何间小吃店
不要覆盖它们。但是在我们的例子中,这个类被扩展了,这样我们就可以实现我们自己的行为。
让我们更详细地了解这个行为类。它的意图是每当开始滚动时,onStartNestedScroll ()
方法将返回真正的
如果滚动是垂直的,从那里onNestedScroll ()
方法将隐藏或显示浮动操作按钮,这取决于它当前的可见状态。
该类的构造函数是该视图行为的重要组成部分,它使该视图从XML文件中扩展
公共FAB_Hide_on_Scroll(上下文上下文,AttributeSetattrs){超级();}
要使用此行为,请添加layout_behavior
属性为浮动操作按钮。该属性包含包名,加上末尾的类名,或者换种说法,该类在项目中的确切位置。在我的例子中,它看起来是这样的:
应用:layout_behavior = " com.valdio.valdioveliu.floatingactionbuttonproject.Scrolling_Floating_Action_Button.FAB_Hide_on_Scroll "
这个动画看起来很酷,但它可以更好。我个人更喜欢在滚动应用内容时将FAB悬浮在屏幕外,这样更真实。我的意思是:
应用了与前面相同的逻辑,只是FAB隐藏更改的方式不同。
动画很简单。FAB在屏幕上垂直漂浮LinearInterpolator.FAB向下浮动一段距离,计算其高度和底边距,以将其完全移出屏幕,并在向上滚动时浮动回其原始位置。
如果您仔细查看代码,会发现我删除了视图。可见
和视图。走了
检查如果
语句,因为视图在这里没有隐藏,只是浮在屏幕外。
公共类FAB_Float_on_Scroll扩展FloatingActionButton.行为{公共FAB_Float_on_Scroll(上下文上下文,AttributeSetattrs){超级();}@Override公共无效onNestedScroll(CoordinatorLayoutcoordinatorLayout,FloatingActionButton孩子,视图目标,intdxConsumed,intdyConsumed,intdxUnconsumed,intdyUnconsumed){超级.onNestedScroll(coordinatorLayout,孩子,目标,dxConsumed,dyConsumed,dxUnconsumed,dyUnconsumed);//child ->浮动动作按钮如果(dyConsumed>0){CoordinatorLayout.LayoutParamslayoutParams=(CoordinatorLayout.LayoutParams)孩子.getLayoutParams();intfab_bottomMargin=layoutParams.页下空白;孩子.动画().translationY(孩子.获得()+fab_bottomMargin).setInterpolator(新LinearInterpolator()).开始();}其他的如果(dyConsumed<0){孩子.动画().translationY(0).setInterpolator(新LinearInterpolator()).开始();}}@Override公共布尔onStartNestedScroll(CoordinatorLayoutcoordinatorLayout,FloatingActionButton孩子,视图directTargetChild,视图目标,intnestedScrollAxes){返回nestedScrollAxes= =ViewCompat.SCROLL_AXIS_VERTICAL;}}
制作一个浮动操作按钮菜单
我见过许多Android应用程序制作了令人印象深刻的浮动操作按钮菜单,它们看起来和运行起来都很好。这里有一个例子:
现在你已经知道我们要做什么了,让我们开始制作吧。
构建这个菜单的第一步是包含3个小按钮的布局。
所有的小按钮都是不可见的,位于布局的底部,在主FAB的下面。
内部fab_layout.xml
<FrameLayoutxmlns:安卓="http://schemas.android.com/apk/res/android"xmlns:应用程序="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.design.widget.FloatingActionButtonandroid:id="@ + id / fab_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="底|结束"android:layout_margin="@dimen / fab_margin"android:src="@android:可拉的/ ic_menu_compass"android:可见性="看不见的"应用:backgroundTint="@color / colorFAB"应用:fabSize="迷你"/><android.support.design.widget.FloatingActionButtonandroid:id="@ + id / fab_2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="底|结束"android:layout_margin="@dimen / fab_margin"android:src="@android:可拉的/ ic_menu_myplaces"android:可见性="看不见的"应用:backgroundTint="@color / colorFAB"应用:fabSize="迷你"/><android.support.design.widget.FloatingActionButtonandroid:id="@ + id / fab_3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="底|结束"android:layout_margin="@dimen / fab_margin"android:src="@android:可拉的/ ic_menu_share"android:可见性="看不见的"应用:backgroundTint="@color / colorFAB"应用:fabSize="迷你"/>FrameLayout>
将此布局包含在活动的布局中,位于主FAB之下。
<包括布局="@layout / fab_layout"/>
现在布局已经设置好了,下一步是制作动画来显示和隐藏每个小fab。
谨慎!
在创建这些动画时,我遇到了触摸事件和小型fab的问题。当动画结束时,小fab的实际位置不会改变,只有视图出现在新位置,所以你不能在正确的位置上执行触摸事件。我解决这个问题的方法是将每个FAB的布局参数设置为其新位置,然后执行将视图拉到新位置的动画。
在本教程的其余部分,我将展示一个小型fab的动画制作过程。其他的过程是相同的,但是有不同的重定位参数。
显示浮动动作按钮菜单
FrameLayout.LayoutParamslayoutParams=(FrameLayout.LayoutParams)fab1.getLayoutParams();layoutParams.rightMargin+ =(int)(fab1.getWidth()*1.7);layoutParams.页下空白+ =(int)(fab1.获得()*0.25);fab1.setLayoutParams(layoutParams);fab1.startAnimation(show_fab_1);fab1.setClickable(真正的);
我在这里重新定位fab1
通过添加右页边距和下页边距layoutParams
然后开始动画。
隐藏浮动动作按钮菜单
FrameLayout.LayoutParamslayoutParams=(FrameLayout.LayoutParams)fab1.getLayoutParams();layoutParams.rightMargin- =(int)(fab1.getWidth()*1.7);layoutParams.页下空白- =(int)(fab1.获得()*0.25);fab1.setLayoutParams(layoutParams);fab1.startAnimation(hide_fab_1);fab1.setClickable(假);
隐藏的过程与前面的动画相反。
在这个FAB上使用的动画是:
/ /动画动画show_fab_1=AnimationUtils.loadAnimation(getApplication(),R.动物.fab1_show);动画hide_fab_1=AnimationUtils.loadAnimation(getApplication(),R.动物.fab1_hide);
现在剩下的就是动画了。在res /动物/文件夹中我为所有动画创建了文件。这些内容并不多,但是如果您需要帮助来理解每个标记或属性的作用,请阅读官方文档文档.
内部fab1_show.xml:
<?XML版本="1.0"编码="utf-8"?><集xmlns:安卓="http://schemas.android.com/apk/res/android"android:fillAfter="真正的"><!——旋转——><旋转android:持续时间="500"android:fromDegrees="30."android:插入器="@android:动画/ linear_interpolator"android:pivotX="50%"android:pivotY="50%"android:repeatCount="4"android:repeatMode="反向"android:toDegrees="0">旋转><!-移动- ><翻译android:持续时间="1000"android:fromXDelta="170%"android:fromYDelta="25%"android:插入器="@android:动画/ linear_interpolator"android:toXDelta="0%"android:toYDelta="0%">翻译><!——淡入><αandroid:持续时间="2000"android:fromAlpha="0.0"android:插入器="@android:动画/ decelerate_interpolator"android:toAlpha="1.0">α>集>
内部fab1_hide.xml:
<?XML版本="1.0"编码="utf-8"?><集xmlns:安卓="http://schemas.android.com/apk/res/android"android:fillAfter="真正的"><!-移动- ><翻译android:持续时间="1000"android:fromXDelta="-170%"android:fromYDelta="-25%"android:插入器="@android:动画/ linear_interpolator"android:toXDelta="0%"android:toYDelta="0%">翻译><!——淡出><αandroid:持续时间="2000"android:fromAlpha="1.0"android:插入器="@android:动画/ accelerate_interpolator"android:toAlpha="0.0">α>集>
最后,如果您查看负责移动视图的翻译标记,我重新定位FAB的因子(170%和25%)对应于java代码中添加和减去的边距因子。
相同的流程适用于其他两个晶圆厂,但重新定位系数为(150%和150%)fab2
和(25%和170%)fab3
.
最终的项目是这样的:
一个新的圆形动画
如果你想用fab制作一些特殊的动画,你可以使用ViewAnimationUtils
类来在视图上显示动画。
本文的其余部分将特别关注这个类以及如何用它构建显示动画。不幸的是,这个类仅适用于API版本21 (LOLLIPOP)及更高版本。
创建一个新活动
由于本文代码示例的其余部分与前面的示例分离,所以我使用了一个新的Activity。如果您决定继续,请创建一个名为RevealActivity
.确保这个活动的布局文件有一个浮动动作按钮,因为我们将利用它来启动动画。在我的例子中,FAB有android: id =“@ + id /工厂”
.
构建Reveal UI
要在视图上显示动画,你需要在动画执行后显示一个布局。
布局取决于你想在应用程序中显示的视图,但为了保持简单,我构建了一个“动画显示”的示例布局。
在布局文件夹中创建一个新文件,fab_reveal_layout.xml
并插入以下代码。
<?XML版本="1.0"编码="utf-8"?><LinearLayoutxmlns:安卓="http://schemas.android.com/apk/res/android"xmlns:应用程序="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@ + id / fabContainerLayout"android:layout_gravity="center_vertical | center_horizontal"android:背景="@color / colorPrimary"android:重力="中心"android:可见性="走了"android:取向="水平"><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"><android.support.design.widget.FloatingActionButtonandroid:id="@ + id / f2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="@dimen / fab_margin"android:layout_marginRight="@dimen / fab_margin"android:src="@android:可拉的/ ic_dialog_email"应用:backgroundTint="@color / colorFAB"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="正确的"android:海拔高度="8 dp"android:文本="Fab2"android:输入textColor="# fff"/>FrameLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:取向="垂直"><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="@dimen / fab_margin"android:layout_marginTop="@dimen / fab_margin"><android.support.design.widget.FloatingActionButtonxmlns:应用程序="http://schemas.android.com/apk/res-auto"android:id="@ + id / f1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="@dimen / fab_margin"android:layout_marginRight="@dimen / fab_margin"android:海拔高度="0 dp"android:src="@android:可拉的/ ic_dialog_map"应用:backgroundTint="@color / colorFAB"应用:borderWidth="0 dp"应用:fabSize="正常的"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="正确的"android:海拔高度="8 dp"android:文本="Fab1"android:输入textColor="# fff"/>FrameLayout><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="@dimen / fab_margin"android:layout_marginTop="@dimen / fab_margin"><android.support.design.widget.FloatingActionButtonandroid:id="@ + id / f4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="@dimen / fab_margin"android:layout_marginRight="@dimen / fab_margin"android:src="@android:可拉的/ ic_dialog_alert"应用:backgroundTint="@color / colorFAB"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="正确的"android:海拔高度="8 dp"android:文本="Fab4"android:输入textColor="# fff"/>FrameLayout>LinearLayout><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"><android.support.design.widget.FloatingActionButtonandroid:id="@ + id / f3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="@dimen / fab_margin"android:layout_marginRight="@dimen / fab_margin"android:src="@android:可拉的/ ic_dialog_dialer"应用:backgroundTint="@color / colorFAB"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="正确的"android:海拔高度="8 dp"android:文本="Fab3"android:输入textColor="# fff"/>FrameLayout>LinearLayout>
实际上,容器LinearLayout
在这个文件中有一个可见性属性可见性= "了"
因此,当您在文件中插入这段代码时,什么也看不见。控件中的可见性属性可检出此布局LinearLayout
或者看看下面的图片。
创建此文件后,将其包含在活动的布局文件中。
activity_reveal.xml
<?XML版本="1.0"编码="utf-8"?> / /……<包括布局="@layout / content_reveal"/><包括布局="@layout / fab_reveal_layout"/><android.support.design.widget.FloatingActionButtonandroid:id="@ + id /工厂"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="底|结束"android:layout_margin="@dimen / fab_margin"android:src="@drawable / ic_add"/>android.support.design.widget.CoordinatorLayout>
设置的RevealActivity
在Activity的布局中包含fab布局后,我们需要设置CircularReveal
动画。
在RevealActivity
类创建以下浮动动作按钮的全局实例布尔
来跟踪动画状态和fab_reveal_layout
容器的布局。
私人LinearLayoutfabContainer;私人FloatingActionButton工厂;私人布尔fabMenuOpen=假;
接下来,在RevealActivity
的onCreate ()
方法来查找FAB的视图引用并添加一个点击监听器。我只启动了活动的FAB,因为这是启动动画所需要的。
@Override受保护的无效onCreate(包savedInstanceState){超级.onCreate(savedInstanceState);/ /……fabContainer=(LinearLayout)findViewById(R.id.fabContainerLayout);工厂=(FloatingActionButton)findViewById(R.id.工厂);工厂.setOnClickListener(新视图.OnClickListener(){@Override公共无效onClick(视图视图){toggleFabMenu();}});}
的toggleFabMenu ()
函数用于创建和启动显示动画。中添加以下代码即可RevealActivity
类,我会详细描述它的功能。
@TargetApi(构建.VERSION_CODES.棒棒糖)私人无效toggleFabMenu(){如果(!fabMenuOpen){工厂.setImageResource(R.可拉的.ic_close);intcenterX=fabContainer.getWidth()/2;intcenterY=fabContainer.获得()/2;intstartRadius=0;intendRadius=(int)数学.函数的(fabContainer.getWidth(),fabContainer.获得())/2;fabContainer.setVisibility(视图.可见);ViewAnimationUtils.createCircularReveal(fabContainer,centerX,centerY,startRadius,endRadius).setDuration(1000).开始();}其他的{工厂.setImageResource(R.可拉的.ic_add);intcenterX=fabContainer.getWidth()/2;intcenterY=fabContainer.获得()/2;intstartRadius=(int)数学.函数的(fabContainer.getWidth(),fabContainer.获得())/2;intendRadius=0;动画师动画师=ViewAnimationUtils.createCircularReveal(fabContainer,centerX,centerY,startRadius,endRadius);动画师.setDuration(1000);动画师.addListener(新动画师.AnimatorListener(){@Override公共无效onAnimationStart(动画师动画){}@Override公共无效onAnimationEnd(动画师动画){fabContainer.setVisibility(视图.走了);}@Override公共无效onAnimationCancel(动画师动画){}@Override公共无效onAnimationRepeat(动画师动画){}});动画师.开始();}fabMenuOpen=!fabMenuOpen;}
正如我之前提到的createCircularReveal ()
方法只适用于LOLLIPOP和更新的Android版本,所以这个函数有一个TargetApi
为构建版本棒棒糖。这意味着当在一个预棒棒糖设备中启动时,这个函数将不会被调用。
这个函数做的第一件事是检查动画视图是否可见fabMenuOpen
布尔
值。
在这个函数中,我改变了工厂
使用setImageResource
()方法。类中添加此函数时,请确保将缺少的图像添加到可拉的
文件夹,或者从函数中注释掉这行代码。
如果您现在运行项目,它将正常工作,如下面的GIF所示,但如果您有兴趣了解如何createCircularReveal ()
请查看本文的下一节。
的ViewAnimationUtils.createCircularReveal ()
方法
的createCircularReveal ()
方法用于设置动画。它接受五个参数,基于它们在视图上创建动画。
第一个参数是对将由动画圈显示的视图的引用。
接下来的两个参数是动画开始时屏幕的X坐标和Y坐标。这些坐标与显示动画的视图相关。
因为动画是一个圆,它需要它正在绘制的圆的半径,所以接下来的两个参数是动画的开始半径和结束半径。
关于本文的示例,如GIF所示,动画将从视图的中心开始,起始半径为“0”,结束半径由Math.hypot ()
方法。要反转动画,只需改变开始和结束半径的值。
循环显示动画的棘手部分是找到与显示动画的视图相关的动画开始。
例如,我计算了动画的X坐标和Y坐标,分别是视图的宽度/2和高度/2,以便找到视图的中心来开始动画。
看看下面的图片,找出如何确定你自己的动画的坐标。
接下来是什么?
我希望我已经给了你一个如何在你自己的项目中动画浮动动作按钮的想法。从这里你应该阅读Android的动画资源为你的应用程序创建你自己的动画。你可以在上面找到这个项目的最终代码GitHub欢迎大家提出任何问题或评论。