android 按钮的隐藏显示,FloatingActionButton滚动时的显示与隐藏小结

FloatingActionButton的显示和隐藏其实很容易谷歌到,之所以写这篇文章是感觉这个知识点有点让人困惑,可以找到多种实现方式,而且兼容包里的FloatingActionButton还不断的变化。

基本来说,如果是使用官方的FloatingActionButton,列表滚动时的显示与隐藏都是使用自定义FloatingActionButton.Behavior来实现的。

NestedScroll的实现方式

我们先来看看比较标准的做法:

首先在xml中定义FloatingActionButton<?xml  version="1.0" encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

android:id="@+id/main_content"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/appbar"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

android:id="@+id/toolbar"

android:layout_width="match_parent"

android:layout_height="?attr/actionBarSize"

android:background="?attr/colorPrimary"

app:popupTheme="@style/ThemeOverlay.AppCompat.Light"

app:layout_scrollFlags="scroll|enterAlways|snap" />

android:id="@+id/tabs"

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:tabGravity="fill"

/>

android:id="@+id/viewpager"

android:layout_width="match_parent"

android:layout_height="match_parent"

app:layout_behavior="@string/appbar_scrolling_view_behavior" />

app:fabSize="normal"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="end|bottom"

android:layout_margin="@dimen/fab_margin"

app:layout_behavior="com.jcodecraeer.fabhideandshow.behavior.ScrollAwareFABBehaviorDefault" />

我们这里使用的是比较常见的toolbar+tab+viewpager布局。

其中ScrollAwareFABBehaviorDefault是我们自定义的一个Behavior。public class ScrollAwareFABBehaviorDefault  extends FloatingActionButton.Behavior{

public ScrollAwareFABBehaviorDefault(Context context, AttributeSet attrs) {

super();

}

@Override

public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,

final View directTargetChild, final View target, final int nestedScrollAxes) {

// Ensure we react to vertical scrolling

return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL

|| super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);

}

@Override

public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,

final View target, final int dxConsumed, final int dyConsumed,

final int dxUnconsumed, final int dyUnconsumed) {

super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);

if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {

// User scrolled down and the FAB is currently visible -> hide the FAB

child.hide();

} else if (dyConsumed 

// User scrolled up and the FAB is currently not visible -> show the FAB

child.show();

}

}

}

然后我们在MainActivity里面写好主界面的其它代码-从github api获取数据,显示列表。Fab在列表滚动时候的显示与隐藏就完成了。看效果

1459997107832837.gif

为什么说这个方法比较官方呢?这是因为在fab显示与隐藏时使用的动画直接借用了FloatingActionButton内置的动画效果,直接在条件恰当的时候调用hide()和show()方法。这两个方法是在22.2.1版本才加进去的,在这之前需要自己写。具体写法参见:http://stackoverflow.com/questions/31381474/menu-and-autohide-floatingactionbutton-of-android-design-support-library 。

然而我并不喜欢这种效果,我更喜欢上下移动的动画方式。

所以我们只能自己定义动画效果了,其实也很简单:public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {

private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();

private boolean mIsAnimatingOut = false;

public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {

super();

}

@Override

public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,

final View directTargetChild, final View target, final int nestedScrollAxes) {

// Ensure we react to vertical scrolling

return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL

|| super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);

}

@Override

public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,

final View target, final int dxConsumed, final int dyConsumed,

final int dxUnconsumed, final int dyUnconsumed) {

super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);

if (dyConsumed > 0 && !this.mIsAnimatingOut && child.getVisibility() == View.VISIBLE) {

// User scrolled down and the FAB is currently visible -> hide the FAB

animateOut(child);

} else if (dyConsumed 

// User scrolled up and the FAB is currently not visible -> show the FAB

animateIn(child);

}

}

// Same animation that FloatingActionButton.Behavior uses to hide the FAB when the AppBarLayout exits

private void animateOut(final FloatingActionButton button) {

if (Build.VERSION.SDK_INT >= 14) {

ViewCompat.animate(button).translationY(button.getHeight() + getMarginBottom(button)).setInterpolator(INTERPOLATOR).withLayer()

.setListener(new ViewPropertyAnimatorListener() {

public void onAnimationStart(View view) {

ScrollAwareFABBehavior.this.mIsAnimatingOut = true;

}

public void onAnimationCancel(View view) {

ScrollAwareFABBehavior.this.mIsAnimatingOut = false;

}

public void onAnimationEnd(View view) {

ScrollAwareFABBehavior.this.mIsAnimatingOut = false;

view.setVisibility(View.GONE);

}

}).start();

} else {

}

}

// Same animation that FloatingActionButton.Behavior uses to show the FAB when the AppBarLayout enters

private void animateIn(FloatingActionButton button) {

button.setVisibility(View.VISIBLE);

if (Build.VERSION.SDK_INT >= 14) {

ViewCompat.animate(button).translationY(0)

.setInterpolator(INTERPOLATOR).withLayer().setListener(null)

.start();

} else {

}

}

private int getMarginBottom(View v) {

int marginBottom = 0;

final ViewGroup.LayoutParams layoutParams = v.getLayoutParams();

if (layoutParams instanceof ViewGroup.MarginLayoutParams) {

marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;

}

return marginBottom;

}

}

效果如下:

1459997241285300.gif

好了,前两种其实都是比较推崇的方式,只是效果不同而已。

Depend的实现方式

下面这种方式也可以实现fab的显示与隐藏,动画接近于上面的第二种效果,但是并不推崇这种方式。

它是这样定义Behavior的:public class ScrollAwareFABBehaviorDepend  extends FloatingActionButton.Behavior{

private int toolbarHeight;

public ScrollAwareFABBehaviorDepend(Context context, AttributeSet attrs) {

super();

this.toolbarHeight = getToolbarHeight(context);

}

@Override

public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {

return super.layoutDependsOn(parent, fab, dependency) || (dependency instanceof AppBarLayout);

}

@Override

public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {

boolean returnValue = super.onDependentViewChanged(parent, fab, 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 returnValue;

}

public static int getToolbarHeight(Context context) {

final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(

new int[]{R.attr.actionBarSize});

int toolbarHeight = (int) styledAttributes.getDimension(0, 0);

styledAttributes.recycle();

return toolbarHeight;

}

}

它的显示与隐藏是根据AppBarLayout的Y值来决定的,我们知道如果按照最上面的方式定义主界面布局,列表滚动的时候toolbar会显示和隐藏,而toolbar是AppBarLayout的一部分,因此可以让Behavior依赖于AppBarLayout,当AppBarLayout变化的时候会调用onDependentViewChanged,然后在这里获取AppBarLayout的高度移动的距离,然后根据这个距离来判定FloatingActionButton上下移动的距离,从而实现了FloatingActionButton的显示和隐藏。这个实现方式我是在这里找到的:http://stackoverflow.com/questions/31457099/android-fab-to-hide-when-navigating-between-different-fragments-in-a-viewpager

代码很简单,但是我并不推崇这种方式,原因:

1.由于只是简单的移动了FloatingActionButton的Y值,效果并不好。

1459997456110505.gif

gif图几乎看不出来和上一种方式的区别。

2.FloatingActionButton依赖于AppBarLayout,如果没有AppBarLayout则会出问题,而且即使有AppBarLayout如果AppBarLayout不会变化也会失效。

3.从逻辑上说FloatingActionButton的显示与隐藏本应该是依赖于列表的滚动的,但是这里却是依赖于AppBarLayout,实际上是列表的滚动让AppBarLayout发生变化,然后AppBarLayout再去通知fab。

不过如果你坚持使用这种方法也没有大问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值