Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: facebook header behaviour- hide header on scroll down, appear on scroll up #37

Open
Bogdastotel opened this issue Oct 12, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@Bogdastotel
Copy link

Bogdastotel commented Oct 12, 2024

Feature Request

Achieve hide header on scroll down and re-appear on scrolling up - Facebook behaviour

Use Case

Facebook header behaviour

Proposed Solution

Can the default behaviour be reverted?

Additional Information

Just look at the fb app

@Bogdastotel Bogdastotel added the enhancement New feature or request label Oct 12, 2024
@Bogdastotel
Copy link
Author

EDIT: one way to make this work is to handle onScrollWorklet to track the scroll direction and change the shared value opacity that we can pass to the Header component as showNavBar value (0 or 1)

@e-younan
Copy link
Member

e-younan commented Oct 14, 2024

Hey there, I won't be able to work on this right now, but isn't this already possible with your approach if you use the absoluteHeader prop too?

This is a little more involved than just doing that, because some features of the ScrollView break (e.g., sticky header indices) when this approach is used. Right now, you can do something like the following:

interface HeaderComponentProps extends ScrollHeaderProps {
  headerTranslationY: SharedValue<number>;
}

const HeaderComponent: React.FC<...> = ({ headerTranslationY }) => {

  const animatedHeaderStyle = useAnimatedStyle(() => {
    // Just translate the header upwards or downwards using the `transform` property using `headerTranslationY `
  });  

  return (
    <Animated.View style={animatedHeaderStyle}>
       <Header ... />
   </Animated.View>
  )
}

and the component is used like so:

const Page = () => {
  const headerTranslationY = useSharedValue(0);

  return (
    <ScrollViewWithHeaders 
      HeaderComponent={hcp => <HeaderComponent {...hcp} headerTranslationY={headerTranslationY} />}
      absoluteHeader
      onScrollWorklet={(event) => {
        "worklet";
        // Adjust the headerTranslationY based on the scroll's event value (use the translation values).
      }}
    />
  )
}

This was all written in the PR editor so the code might not be accurate, but it is generally what you should do to achieve that.

@Bogdastotel
Copy link
Author

Bogdastotel commented Oct 15, 2024

@e-younan thanks for the suggestion, i will also try this approach, for now what i did was just tracking scroll direction and passing the showNavBar opacity to the Header component:

``export const HeaderTest = () => {
const { bottom } = useSafeAreaInsets();
const previousOffsetY = useSharedValue(0);
const sharedValue = useSharedValue(1);
const [contentHeight, setContentHeight] = useState(0);
const [scrollViewHeight, setScrollViewHeight] = useState(0);
let hideHeaderTimeout = null; // Regular variable, not a ref
const insets = useSafeAreaInsets();

const onContentSizeChange = (width: number, height: number) => {
setContentHeight(height);
};

const onLayout = (evt: LayoutChangeEvent) => {
const { height } = evt.nativeEvent.layout;
setScrollViewHeight(height);
};

const scrollHandlerWorklet = (evt: NativeScrollEvent) => {
'worklet';

const currentScrollY = evt.contentOffset.y;
const maxOffsetY = contentHeight - scrollViewHeight;
const clampedOffsetY = Math.max(0, Math.min(currentScrollY, maxOffsetY));

const deltaY = currentScrollY - previousOffsetY.value;

const isNearTop = currentScrollY <= 100;

if (isNearTop) {
  sharedValue.value = 1; // Show the header when near the top
} else if (deltaY > 10) {
  sharedValue.value = 0; // Hide header when scrolling down
} else if (deltaY < -10) {
  sharedValue.value = 1; // Show header when scrolling up
}

// Update the previous offset value for the next scroll event
previousOffsetY.value = clampedOffsetY;

};

return (
<ScrollViewWithHeaders
absoluteHeader={true}
onLayout={onLayout}
onContentSizeChange={onContentSizeChange} // Capture content height
onScrollWorklet={scrollHandlerWorklet}
HeaderComponent={() => }
contentContainerStyle={{ paddingBottom: bottom, paddingTop: 150 }}>
<View style={{ padding: 16, flex: 1 }}>
{Array.from({ length: 50 }, (_, i) => (
<View
style={{
height: 200,
backgroundColor: 'blue',
marginVertical: 10,
}}>
Some item...

))}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants