Skip to content

Commit 21f9b0f

Browse files
imhappiafohrman
authored andcommitted
[BottomAppBar] Add a callback for whenever bottom view hides/unhides through scrolling
PiperOrigin-RevId: 450449206
1 parent 382ce9c commit 21f9b0f

File tree

2 files changed

+104
-5
lines changed

2 files changed

+104
-5
lines changed

lib/java/com/google/android/material/behavior/HideBottomViewOnScrollBehavior.java

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.android.material.behavior;
1818

19+
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20+
1921
import android.animation.Animator;
2022
import android.animation.AnimatorListenerAdapter;
2123
import android.animation.TimeInterpolator;
@@ -25,27 +27,64 @@
2527
import android.view.ViewGroup;
2628
import android.view.ViewPropertyAnimator;
2729
import androidx.annotation.Dimension;
30+
import androidx.annotation.IntDef;
2831
import androidx.annotation.NonNull;
2932
import androidx.annotation.Nullable;
33+
import androidx.annotation.RestrictTo;
3034
import androidx.coordinatorlayout.widget.CoordinatorLayout;
3135
import androidx.coordinatorlayout.widget.CoordinatorLayout.Behavior;
3236
import androidx.core.view.ViewCompat;
3337
import com.google.android.material.animation.AnimationUtils;
38+
import java.util.LinkedHashSet;
3439

3540
/**
3641
* The {@link Behavior} for a View within a {@link CoordinatorLayout} to hide the view off the
3742
* bottom of the screen when scrolling down, and show it when scrolling up.
3843
*/
3944
public class HideBottomViewOnScrollBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
4045

46+
/**
47+
* Interface definition for a listener to be notified when the bottom view scroll state
48+
* changes.
49+
*/
50+
public interface OnScrollStateChangedListener {
51+
52+
/**
53+
* Called when the bottom view changes its scrolled state.
54+
*
55+
* @param bottomView The bottom view.
56+
* @param newState The new state. This will be one of {@link #STATE_SCROLLED_UP} or {@link
57+
* #STATE_SCROLLED_DOWN}.
58+
*/
59+
void onStateChanged(@NonNull View bottomView, @ScrollState int newState);
60+
}
61+
62+
@NonNull
63+
private final LinkedHashSet<OnScrollStateChangedListener> onScrollStateChangedListeners =
64+
new LinkedHashSet<>();
65+
4166
protected static final int ENTER_ANIMATION_DURATION = 225;
4267
protected static final int EXIT_ANIMATION_DURATION = 175;
4368

44-
private static final int STATE_SCROLLED_DOWN = 1;
45-
private static final int STATE_SCROLLED_UP = 2;
69+
/** State of the bottom view when it's scrolled down. */
70+
public static final int STATE_SCROLLED_DOWN = 1;
71+
/**
72+
* State of the bottom view when it's scrolled up.
73+
*/
74+
public static final int STATE_SCROLLED_UP = 2;
4675

4776
private int height = 0;
48-
private int currentState = STATE_SCROLLED_UP;
77+
78+
/**
79+
* Positions the scroll state can be set to.
80+
*
81+
* @hide
82+
*/
83+
@RestrictTo(LIBRARY_GROUP)
84+
@IntDef({STATE_SCROLLED_DOWN, STATE_SCROLLED_UP})
85+
public @interface ScrollState {}
86+
87+
@ScrollState private int currentState = STATE_SCROLLED_UP;
4988
private int additionalHiddenOffsetY = 0;
5089
@Nullable private ViewPropertyAnimator currentAnimator;
5190

@@ -135,7 +174,7 @@ public void slideUp(@NonNull V child, boolean animate) {
135174
currentAnimator.cancel();
136175
child.clearAnimation();
137176
}
138-
currentState = STATE_SCROLLED_UP;
177+
updateCurrentState(child, STATE_SCROLLED_UP);
139178
int targetTranslationY = 0;
140179
if (animate) {
141180
animateChildTo(
@@ -176,7 +215,7 @@ public void slideDown(@NonNull V child, boolean animate) {
176215
currentAnimator.cancel();
177216
child.clearAnimation();
178217
}
179-
currentState = STATE_SCROLLED_DOWN;
218+
updateCurrentState(child, STATE_SCROLLED_DOWN);
180219
int targetTranslationY = height + additionalHiddenOffsetY;
181220
if (animate) {
182221
animateChildTo(
@@ -189,6 +228,13 @@ public void slideDown(@NonNull V child, boolean animate) {
189228
}
190229
}
191230

231+
private void updateCurrentState(@NonNull V child, @ScrollState int state) {
232+
currentState = state;
233+
for (OnScrollStateChangedListener listener : onScrollStateChangedListeners) {
234+
listener.onStateChanged(child, currentState);
235+
}
236+
}
237+
192238
private void animateChildTo(
193239
@NonNull V child, int targetY, long duration, TimeInterpolator interpolator) {
194240
currentAnimator =
@@ -205,4 +251,27 @@ public void onAnimationEnd(Animator animation) {
205251
}
206252
});
207253
}
254+
255+
/**
256+
* Adds a listener to be notified of bottom view scroll state changes.
257+
*
258+
* @param listener The listener to notify when bottom view scroll state changes.
259+
*/
260+
public void addOnScrollStateChangedListener(@NonNull OnScrollStateChangedListener listener) {
261+
onScrollStateChangedListeners.add(listener);
262+
}
263+
264+
/**
265+
* Removes a previously added listener.
266+
*
267+
* @param listener The listener to remove.
268+
*/
269+
public void removeOnScrollStateChangedListener(@NonNull OnScrollStateChangedListener listener) {
270+
onScrollStateChangedListeners.remove(listener);
271+
}
272+
273+
/** Remove all previously added {@link OnScrollStateChangedListener}s. */
274+
public void clearOnScrollStateChangedListeners() {
275+
onScrollStateChangedListeners.clear();
276+
}
208277
}

lib/java/com/google/android/material/bottomappbar/BottomAppBar.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import com.google.android.material.animation.AnimationUtils;
5959
import com.google.android.material.animation.TransformationCallback;
6060
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior;
61+
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior.OnScrollStateChangedListener;
6162
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
6263
import com.google.android.material.floatingactionbutton.FloatingActionButton;
6364
import com.google.android.material.floatingactionbutton.FloatingActionButton.OnVisibilityChangedListener;
@@ -541,6 +542,35 @@ public boolean isScrolledUp() {
541542
return getBehavior().isScrolledUp();
542543
}
543544

545+
/**
546+
* Add a listener that will be called when the bottom app bar scroll state changes.
547+
* See {@link OnScrollStateChangedListener}.
548+
*
549+
* <p>Components that add a listener should take care to remove it when finished via {@link
550+
* #removeOnScrollStateChangedListener(OnScrollStateChangedListener)}.
551+
*
552+
* @param listener listener to add
553+
*/
554+
public void addOnScrollStateChangedListener(@NonNull OnScrollStateChangedListener listener) {
555+
getBehavior().addOnScrollStateChangedListener(listener);
556+
}
557+
558+
/**
559+
* Remove a listener that was previously added via {@link
560+
* #addOnScrollStateChangedListener(OnScrollStateChangedListener)}.
561+
*
562+
* @param listener listener to remove
563+
*/
564+
public void removeOnScrollStateChangedListener(
565+
@NonNull OnScrollStateChangedListener listener) {
566+
getBehavior().removeOnScrollStateChangedListener(listener);
567+
}
568+
569+
/** Remove all previously added {@link OnScrollStateChangedListener}s. */
570+
public void clearOnScrollStateChangedListeners() {
571+
getBehavior().clearOnScrollStateChangedListeners();
572+
}
573+
544574
@Override
545575
public void setElevation(float elevation) {
546576
materialShapeDrawable.setElevation(elevation);

0 commit comments

Comments
 (0)