在上一篇文章中,我们介绍了一种实现FloatingActionButton随内容滚动隐藏的办法,原理是为FAB添加行为属性(behavior),通过对内容的滚动监控来实现隐藏。但是这种办法有一个缺点就是,当item比较少的时候,少到屏幕就能显示所有内容,不会产生滚动,这样FAB就无法隐藏了,可能遮住最后一项要显示的内容。
本文我们将介绍另一种办法,让FAB随toolbar的隐藏而实现隐藏,而不是依赖内容。先上效果图:
准备
首先先把状态栏设置为非透明的,这样toolbar上滑出去标题跟状态栏不会重叠,而是被覆盖。将style(v21)中的
<item name="android:statusBarColor">@android:color/transparent</item>
改为:
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
属性设置
然后设置Toolbar随滚动操作退出屏幕,在activity_main中的Toolbar组间中加入如下属性:
app:layout_scrollFlags="scroll|enterAlways"
一切就绪后,就开始写行为属性类,代码如下:
public class ScrollingFABBehavior extends CoordinatorLayout.Behavior<FloatingActionsMenu> {
//定义toolbar高度和状态栏高度
private int toolbarHeight;
private double statusBarHeight;
public ScrollingFABBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
//得到两个高度值
this.toolbarHeight = getToolbarHeight(context);
this.statusBarHeight=getStatusBarHeight(context);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionsMenu fab, View dependency) {
//设定依赖的父布局为AppBarLayout
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionsMenu fab, View dependency) {
if (dependency instanceof AppBarLayout) {
//FAB的自身高度+据底边高度的和=要实现FAB隐藏需要向下移动的距离
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
int distanceToScroll = fab.getHeight() + fabBottomMargin;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
//toolbar被移走的距离与本身高度的比值
float ty=dependency.getY()-(float)statusBarHeight;
float ratio = ty / (float) toolbarHeight;
//toolbar被移走几分之几,fab就向下滑几分之几
fab.setTranslationY(-distanceToScroll * ratio);
}
}
return true;
}
private int getToolbarHeight(Context context){
TypedValue tv = new TypedValue();
int actionBarHeight = android.support.v7.appcompat.R.attr.actionBarSize;
if (context.getTheme().resolveAttribute(R.attr.actionBarSize, tv, true))
{
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
context.getResources().getDisplayMetrics());
}
return actionBarHeight;
}
//状态栏高度的方法
private int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}
具体办法注释中已经说明了。
然后将FAB的行为属性改成:
app:layout_behavior="com.android.wangkang.fabdemo.ScrollingFABBehavior"
至此运行应用,就能得到上面的效果。
后记
这种方法是参考这篇文章中的办法:https://mzgreen.github.io/2015/06/23/How-to-hideshow-Toolbar-when-list-is-scrolling(part3)/
刚开始直接复制该文章中的ScrollingFABBehavior类,复制过来并将FAB设置为该属性后,发现启动时FAB并不在原位置,而是向上偏移了很多。该文章中关于FAB的隐藏方法如下:
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
if (dependency instanceof AppBarLayout) {
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
int distanceToScroll = fab.getHeight() + fabBottomMargin;
float ratio = (float)dependency.getY()/(float)toolbarHeight;
fab.setTranslationY(-distanceToScroll * ratio);
}
return true;
}
设置断点后发现应用启动时dependency.getY()并不是0而是75,查资料后发现75是状态栏高度。后来google后找到了几种得到状态栏高度的办法,在初始计算时减去即可。修改后的方法为:
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionsMenu fab, View dependency) {
if (dependency instanceof AppBarLayout) {
//FAB的自身高度+据底边高度的和=要实现FAB隐藏需要向下移动的距离
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
int distanceToScroll = fab.getHeight() + fabBottomMargin;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
//toolbar被移走的距离与本身高度的比值
float ty=dependency.getY()-(float)statusBarHeight;
float ratio = ty / (float) toolbarHeight;
//toolbar被移走几分之几,fab就向下滑几分之几
fab.setTranslationY(-distanceToScroll * ratio);
}
}
return true;
}
我的这篇文章介绍了两种获得状态栏高度的办法。
Demo放在:https://github.com/w-kahn/FABDemo/tree/OtherHide