FloatingActionButton滚动时的显示与隐藏小结
来源:互联网 发布:使用数据库 编辑:程序博客网 时间:2024/05/19 13:22
编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!
FloatingActionButton的显示和隐藏其实很容易谷歌到,之所以写这篇文章是感觉这个知识点有点让人困惑,可以找到多种实现方式,而且兼容包里的FloatingActionButton还不断的变化。
基本来说,如果是使用官方的FloatingActionButton,列表滚动时的显示与隐藏都是使用自定义FloatingActionButton.Behavior来实现的。
NestedScroll的实现方式
我们先来看看比较标准的做法:
首先在xml中定义FloatingActionButton
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- ~ Copyright (C) 2015 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
- <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
- 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.support.design.widget.AppBarLayout
- android:id="@+id/appbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
- <android.support.v7.widget.Toolbar
- 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.support.design.widget.TabLayout
- android:id="@+id/tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:tabGravity="fill"
- />
- </android.support.design.widget.AppBarLayout>
- <android.support.v4.view.ViewPager
- android:id="@+id/viewpager"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:layout_behavior="@string/appbar_scrolling_view_behavior" />
- <android.support.design.widget.FloatingActionButton
- 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" />
- </android.support.design.widget.CoordinatorLayout>
我们这里使用的是比较常见的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 < 0 && child.getVisibility() != View.VISIBLE) {
- // User scrolled up and the FAB is currently not visible -> show the FAB
- child.show();
- }
- }
- }
然后我们在MainActivity里面写好主界面的其它代码-从github api获取数据,显示列表。Fab在列表滚动时候的显示与隐藏就完成了。看效果
为什么说这个方法比较官方呢?这是因为在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 < 0 && child.getVisibility() != View.VISIBLE) {
- // 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;
- }
- }
效果如下:
好了,前两种其实都是比较推崇的方式,只是效果不同而已。
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值,效果并不好。
gif图几乎看不出来和上一种方式的区别。
2.FloatingActionButton依赖于AppBarLayout,如果没有AppBarLayout则会出问题,而且即使有AppBarLayout如果AppBarLayout不会变化也会失效。
3.从逻辑上说FloatingActionButton的显示与隐藏本应该是依赖于列表的滚动的,但是这里却是依赖于AppBarLayout,实际上是列表的滚动让AppBarLayout发生变化,然后AppBarLayout再去通知fab。
不过如果你坚持使用这种方法也没有大问题。
- FloatingActionButton滚动时的显示与隐藏小结
- FloatingActionButton滚动时的显示与隐藏小结
- FloatingActionButton滚动时的显示与隐藏
- FloatingActionButton的滚动隐藏和弹出特效的实现
- FloatingActionButton的滚动隐藏和弹出特效的实现
- FloatingActionButton滚动隐藏的另一种实现方法:依赖appBarLayout
- CoordinatorLayout、FloatingActionButton实现上滑隐藏FloatingActionButton,下滑显示FloatingActionButton
- 滚动条控制 div的显示与隐藏。
- div动态显示与隐藏时防止滚动条回滚
- 滚动时自动显示与隐藏导航条定制
- Android FloatingActionButton下拉隐藏后,上拉不显示
- UITableView 滚动时,显示隐藏UINavigaionbar的方法
- FloatingActionButton属性、用法,以及解析并解决sdk25以上只隐藏不显示的问题
- DIV 滚动条的自动显示隐藏
- iframe的滚动条问题:显示/隐藏滚动条
- iframe的滚动条问题:显示/隐藏滚动条
- iframe的滚动条问题:显示/隐藏滚动条
- FloatingActionButton自定义滑动动画,只隐藏不显示解决方案
- Hadoop RPC测试
- Win7x64系统下Synplify正常工作的一种解决方法
- JavaScript 类型相关(数据类型,类型转换等)
- elk日志分析服务器部署
- RPC原理及RPC实例分析
- FloatingActionButton滚动时的显示与隐藏小结
- 梦想
- 如何使用Eclipse最简单地配置其他语言的IDE环境:例子-Python
- udp和tcp的区别
- 欢迎使用CSDN-markdown编辑器
- 添加事务管理
- TCP和UDP详解
- GOLANG项目:文本排序程序
- Fuel手动安装Mirantis(openstack) 7.0,如何访问FuelWebUI