Skip to content
This repository was archived by the owner on Jan 20, 2021. It is now read-only.

Commit aefa8b5

Browse files
Makes main activity FAB scroll aware
Hides the FAB when the user scrolls down and shows it when they scroll back up. Reuses the same animation that FloatingActionButton.Behavior uses for hiding/showing the FAB in reaction to the AppBarLayout exiting/entering.
1 parent 4dfeabf commit aefa8b5

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2015 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.support.android.designlibdemo;
17+
18+
import android.content.Context;
19+
import android.os.Build;
20+
import android.support.design.widget.CoordinatorLayout;
21+
import android.support.design.widget.FloatingActionButton;
22+
import android.support.v4.view.ViewCompat;
23+
import android.support.v4.view.ViewPropertyAnimatorListener;
24+
import android.support.v4.view.animation.FastOutSlowInInterpolator;
25+
import android.util.AttributeSet;
26+
import android.view.View;
27+
import android.view.animation.Animation;
28+
import android.view.animation.AnimationUtils;
29+
import android.view.animation.Interpolator;
30+
31+
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
32+
private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
33+
private boolean mIsAnimatingOut = false;
34+
35+
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
36+
super();
37+
}
38+
39+
@Override
40+
public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
41+
final View directTargetChild, final View target, final int nestedScrollAxes) {
42+
// Ensure we react to vertical scrolling
43+
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
44+
|| super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
45+
}
46+
47+
@Override
48+
public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
49+
final View target, final int dxConsumed, final int dyConsumed,
50+
final int dxUnconsumed, final int dyUnconsumed) {
51+
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
52+
if (dyConsumed > 0 && !this.mIsAnimatingOut && child.getVisibility() == View.VISIBLE) {
53+
// User scrolled down and the FAB is currently visible -> hide the FAB
54+
animateOut(child);
55+
} else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
56+
// User scrolled up and the FAB is currently not visible -> show the FAB
57+
animateIn(child);
58+
}
59+
}
60+
61+
// Same animation that FloatingActionButton.Behavior uses to hide the FAB when the AppBarLayout exits
62+
private void animateOut(final FloatingActionButton button) {
63+
if (Build.VERSION.SDK_INT >= 14) {
64+
ViewCompat.animate(button).scaleX(0.0F).scaleY(0.0F).alpha(0.0F).setInterpolator(INTERPOLATOR).withLayer()
65+
.setListener(new ViewPropertyAnimatorListener() {
66+
public void onAnimationStart(View view) {
67+
ScrollAwareFABBehavior.this.mIsAnimatingOut = true;
68+
}
69+
70+
public void onAnimationCancel(View view) {
71+
ScrollAwareFABBehavior.this.mIsAnimatingOut = false;
72+
}
73+
74+
public void onAnimationEnd(View view) {
75+
ScrollAwareFABBehavior.this.mIsAnimatingOut = false;
76+
view.setVisibility(View.GONE);
77+
}
78+
}).start();
79+
} else {
80+
Animation anim = AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_out);
81+
anim.setInterpolator(INTERPOLATOR);
82+
anim.setDuration(200L);
83+
anim.setAnimationListener(new Animation.AnimationListener() {
84+
public void onAnimationStart(Animation animation) {
85+
ScrollAwareFABBehavior.this.mIsAnimatingOut = true;
86+
}
87+
88+
public void onAnimationEnd(Animation animation) {
89+
ScrollAwareFABBehavior.this.mIsAnimatingOut = false;
90+
button.setVisibility(View.GONE);
91+
}
92+
93+
@Override
94+
public void onAnimationRepeat(final Animation animation) {
95+
}
96+
});
97+
button.startAnimation(anim);
98+
}
99+
}
100+
101+
// Same animation that FloatingActionButton.Behavior uses to show the FAB when the AppBarLayout enters
102+
private void animateIn(FloatingActionButton button) {
103+
button.setVisibility(View.VISIBLE);
104+
if (Build.VERSION.SDK_INT >= 14) {
105+
ViewCompat.animate(button).scaleX(1.0F).scaleY(1.0F).alpha(1.0F)
106+
.setInterpolator(INTERPOLATOR).withLayer().setListener(null)
107+
.start();
108+
} else {
109+
Animation anim = AnimationUtils.loadAnimation(button.getContext(), R.anim.fab_in);
110+
anim.setDuration(200L);
111+
anim.setInterpolator(INTERPOLATOR);
112+
button.startAnimation(anim);
113+
}
114+
}
115+
}

app/src/main/res/layout/include_list_viewpager.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
android:layout_height="wrap_content"
5555
android:layout_gravity="end|bottom"
5656
android:layout_margin="@dimen/fab_margin"
57-
android:src="@drawable/ic_done" />
57+
android:src="@drawable/ic_done"
58+
app:layout_behavior="com.support.android.designlibdemo.ScrollAwareFABBehavior" />
5859

5960
</android.support.design.widget.CoordinatorLayout>

0 commit comments

Comments
 (0)