Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
react-native-action-button hide on scroll
// 1. Define a state variable for showing/hiding the action-button
state = {
isActionButtonVisible: true
}
// 2. Define a variable that will keep track of the current scroll position
_listViewOffset = 0
// 3. Add an onScroll listener to your listview/scrollview
<ListView
...
onScroll={this._onScroll}
...
/>
// 3. Add some logic in the scroll listener for hiding the action button when scrolling down
_onScroll = (event) => {
// Simple fade-in / fade-out animation
const CustomLayoutLinear = {
duration: 100,
create: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
update: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
delete: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity }
}
// Check if the user is scrolling up or down by confronting the new scroll position with your own one
const currentOffset = event.nativeEvent.contentOffset.y
const direction = (currentOffset > 0 && currentOffset > this._listViewOffset)
? 'down'
: 'up'
// If the user is scrolling down (and the action-button is still visible) hide it
const isActionButtonVisible = direction === 'up'
if (isActionButtonVisible !== this.state.isActionButtonVisible) {
LayoutAnimation.configureNext(CustomLayoutLinear)
this.setState({ isActionButtonVisible })
}
// Update your scroll position
this._listViewOffset = currentOffset
}
// 4. In you render show you action-button only if state.isActionButtonVisible === true
<View style={styles.container}>
{yourListView}
{this.state.isActionButtonVisible ? <ActionButton /> : null}
</View>
@mmazzarolo
Copy link
Author

mmazzarolo commented Sep 19, 2016

fab-hide-show

@mmazzarolo
Copy link
Author

mmazzarolo commented Sep 19, 2016

It can be tweaked further for handling the bottom "bounce" of the iOS scrollview (the top one is handled by currentOffset > 0.
The tweak might consist in a mix of checking if the bottom of the scrollview is visible and checking the scrollview content height.

@ufon
Copy link

ufon commented Oct 24, 2016

for android put in constructor:
UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);

@pewh
Copy link

pewh commented Dec 29, 2016

When I set backdrop props on <ActionButton .. />, it will trigger backdrop every scroll to top. Is it a bug from the component itself?

Uploading asd.gif…

@pewh
Copy link

pewh commented Dec 29, 2016

asd

@ruxiang05
Copy link

ruxiang05 commented Mar 4, 2017

I am given this error but I don't really understand what I should do.

You specified onScroll on a but not scrollEventThrottle. You will only receive one event. Using 16 you get all the events but be aware that it may cause frame drops, use a bigger number if you don't need as much precision.

@damikdk
Copy link

damikdk commented Sep 19, 2017

@ruxiang05 this warning is about update frequency on iOS. The less the more often (docs)

@mmazzarolo, thanks for code!

@kkkevinnn
Copy link

kkkevinnn commented Jan 25, 2018

I have fixed the bottom bounce issue based on this
https://gist.github.com/hisokakei/25ace65e3df656313990b710354e1541

@rsp8055
Copy link

rsp8055 commented Apr 5, 2018

How to show alphabet bubble in scroll bar indicator

@inferusvv
Copy link

inferusvv commented Nov 24, 2019

On iOS we have bounce effect. So I improved a bit:

    const isBottomBounce =
      event.nativeEvent.layoutMeasurement.height -
        event.nativeEvent.contentSize.height +
        event.nativeEvent.contentOffset.y >=
      0;


    let direction = currentOffset > 0 && currentOffset > this.listViewOffset ? 'down' : 'up';
    if (direction === 'up' && isBottomBounce) {
      direction = 'down';
    }

@hmoule
Copy link

hmoule commented Feb 18, 2020

For those using functional components you could turn it into a hook like this

import { useState, useRef, useCallback } from 'react';
import { NativeSyntheticEvent, NativeScrollEvent, LayoutAnimation } from 'react-native';

const useHandleScroll = () => {
  const [showButton, setShowButton] = useState(true);

  const scrollOffset = useRef(0);

  const handleScroll = useCallback(
    (event: NativeSyntheticEvent<NativeScrollEvent>) => {
      const CustomLayoutLinear = {
        duration: 100,
        create: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
        update: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
        delete: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
      };
      // Check if the user is scrolling up or down by confronting the new scroll position with your own one
      const currentOffset = event.nativeEvent.contentOffset.y;
      const direction = currentOffset > 0 && currentOffset > scrollOffset.current ? 'down' : 'up';
      // If the user is scrolling down (and the action-button is still visible) hide it
      const isActionButtonVisible = direction === 'up';
      if (isActionButtonVisible !== showButton) {
        LayoutAnimation.configureNext(CustomLayoutLinear);
        setShowButton(isActionButtonVisible);
      }
      // Update your scroll position
      scrollOffset.current = currentOffset;
    },
    [showButton]
  );

  return { handleScroll, showButton };
};

export default useHandleScroll;

and then use it like this

const { handleScroll, showButton } = useHandleScroll();

<ScrollView onScroll={handleScroll} />
{showButton && <Button />}

@Madhu02
Copy link

Madhu02 commented Nov 15, 2020

@hmoule

For those using functional components you could turn it into a hook like this

import { useState, useRef, useCallback } from 'react';
import { NativeSyntheticEvent, NativeScrollEvent, LayoutAnimation } from 'react-native';

const useHandleScroll = () => {
  const [showButton, setShowButton] = useState(true);

  const scrollOffset = useRef(0);

  const handleScroll = useCallback(
    (event: NativeSyntheticEvent<NativeScrollEvent>) => {
      const CustomLayoutLinear = {
        duration: 100,
        create: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
        update: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
        delete: { type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity },
      };
      // Check if the user is scrolling up or down by confronting the new scroll position with your own one
      const currentOffset = event.nativeEvent.contentOffset.y;
      const direction = currentOffset > 0 && currentOffset > scrollOffset.current ? 'down' : 'up';
      // If the user is scrolling down (and the action-button is still visible) hide it
      const isActionButtonVisible = direction === 'up';
      if (isActionButtonVisible !== showButton) {
        LayoutAnimation.configureNext(CustomLayoutLinear);
        setShowButton(isActionButtonVisible);
      }
      // Update your scroll position
      scrollOffset.current = currentOffset;
    },
    [showButton]
  );

  return { handleScroll, showButton };
};

export default useHandleScroll;

and then use it like this

const { handleScroll, showButton } = useHandleScroll();

<ScrollView onScroll={handleScroll} />
{showButton && <Button />}

Could you please help me in converting the above code into Class Component unable to use the Hook in class.

@risardi123
Copy link

risardi123 commented Nov 16, 2020

Thanks, @hmoule

@aravi365
Copy link

aravi365 commented Nov 19, 2020

On iOS we have bounce effect. So I improved a bit:

    const isBottomBounce =
      event.nativeEvent.layoutMeasurement.height -
        event.nativeEvent.contentSize.height +
        event.nativeEvent.contentOffset.y >=
      0;


    let direction = currentOffset > 0 && currentOffset > this.listViewOffset ? 'down' : 'up';
    if (direction === 'up' && isBottomBounce) {
      direction = 'down';
    }

By adding this code with @hmoule 's code i am getting a weird jump effect in android when started scrolling. Any way to avoid that? it works perfectly on iOS

@aravi365
Copy link

aravi365 commented Nov 19, 2020

@aravi365
Copy link

aravi365 commented Nov 19, 2020

Its run perfect on my android @aravi365
make sure on your scrollview Props looks like this
onScroll={handleScroll.bind(this)}

it happens only when scrolling slowly. Works like normal when scrolled in normal speed. My usecase is not an action button, instead it is a tabbar which autohides on scrolldown. That might be the root cause of this issue? any guesses

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment