osdnk / react-native-reanimated-bottom-sheet

Highly configurable bottom sheet component made with react-native-reanimated and react-native-gesture-handler
MIT License
3.33k stars 328 forks source link

Present above [native] tab bar #143

Closed oferRounds closed 4 years ago

oferRounds commented 4 years ago

Hi, I’m using react native navigation – everything works great, except for the fact the bottom sheet is presented beneath the tab bar. Is there a way to make it show above it?

Thank you!

zmnv commented 4 years ago

The same as https://github.com/osdnk/react-native-reanimated-bottom-sheet/issues/60

oferRounds commented 4 years ago

@zmnv I saw this issue, but I don‘t think it’s the same... This relates to a native tab bar, the issue you refer to relate to a non-native tab bar

zmnv commented 4 years ago

@oferRounds what is a 'native tab bar'?

You mean bottom navigation bar in android?

oferRounds commented 4 years ago

Yes, but only on iOS

On iOS it’s called TabBar, and as react-native-navigation is based on the native iOS’ TabBar and Android‘s BottomNavigationBar, then it’s a different story compared to react-navigation JS solution

zmnv commented 4 years ago

No matter iOS or Android. TabBar or BottomNavigationBar always inside <Navigation />.

You just need to place your bottom sheet ABOVE <Navigation /> component. Outside of Navigation Stack like in https://github.com/brentvatne/bottom-sheet-example/blob/master/App.tsx#L201

oferRounds commented 4 years ago

Well react-native-navigation works a bit differently, there’s no tag, not sure about how to place it outside. But let me check further...

oferRounds commented 4 years ago

@zmnv seems like there’s no good way to integrate your react-native-reanimated-bottom-sheet with react-native-navigation (see here: https://github.com/wix/react-native-navigation/issues/5789)

Perhaps we can change react-native-reanimated-bottom-sheet in the way that it will always (by default) present the sheet on the front? i.e., on its native implementation (on iOS, perhaps setting the windowLevel to Alert)

zmnv commented 4 years ago

It doesn't matter which navigation you use... react-native-reanimated-bottom-sheet is just view component

oferRounds commented 4 years ago

I see now that there is no native side... It does in the sense that it get presented bellow the tab bar... Perhaps it should use React Native‘s Modal component?

oferRounds commented 4 years ago

was manage to solve the issue by wrapping the component in a Modal component... Could be that this should be included in the component...

BrtqKr commented 4 years ago

Hi, thank you for digging into this issue. Your problem seems to be caused entirely by react native navigation and that's why it has to be wrapped in a Modal component. Please use react navigation next time instead. I think that sums it up.

zmnv commented 4 years ago

You can handle 'back' button on Android to close bottom sheet

AndroidBackHandler.tsx

import React, { PureComponent } from 'react';

import { BackHandler } from 'react-native';
import { NavigationEvents } from 'react-navigation';

type Props = {
    onBackPress: () => void,
};

export class AndroidBackHandler extends PureComponent<Props> {

    enabled = true;
    backHandler: any;

    componentDidMount() {
        this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
    }

    componentWillUnmount() {
        this.backHandler.remove();
    }

    handleBackPress = () => {
        if (this.enabled && this.props.onBackPress) {

            this.props.onBackPress();
            return true;
        }

        return false;
    }

    handleWillBlur = () => {
        this.enabled = false;
    }

    handleWillFocus = () => {
        this.enabled = true;
    }

    render() {
        return (
            <NavigationEvents
                onWillFocus={this.handleWillFocus}
                onWillBlur={this.handleWillBlur}
            />
        );
    }
}
oferRounds commented 4 years ago

@BrtqKr react-native-navigation is a popular library... Anyhow, wrap it in a modal solves the issue

@zmnv your last answer might be related to a different issue?

zmnv commented 4 years ago

@oferRounds yes, it's good to put inside render to handle back navigation when component rendered.

image

So, when bottom sheet is opened hardware back button will hide it. You can put tab slider and handle 'routing' (not actually navigation, but still...) inside bottom sheet.

ps: <FadeInOut /> don't mount children if visible = false.

BrtqKr commented 4 years ago

@oferRounds indeed it is, but when you use react native navigation your bottomsheet is going to be rendered with a different hierarchy and is going to be displayed as you described.

zmnv commented 4 years ago

@oferRounds Do you mean modal like https://reactnavigation.org/docs/en/modal.html ? With transparent background.

oferRounds commented 4 years ago

@zmnv thanks – no, I mean https://github.com/react-native-community/react-native-modal

mstaicu commented 4 years ago

Care to share the boilerplate code used to achieve this @oferRounds ? I'm pretty sure there are other people facing this issue!

oferRounds commented 4 years ago

@mstaicu sorry missed your comment! Here it is:

<Modal
                useNativeDriver = { true }
                style = { styles.modal }
                isVisible = { this.state.isPresentingReactionsPickerBottomsheet }
                onBackButtonPress = { this.onReactionsPickerBottomSheetClose }
                onBackdropPress = { this.onReactionsPickerBottomSheetClose }
            >
                <BottomSheet
                    ref = { this.onGetReactionsPickerBottomSheetRef }
                    snapPoints = { [USERS_REACTIONS_BOTTOM_SHEET_INITIAL_HEIGHT, USERS_REACTIONS_BOTTOM_SHEET_INITIAL_HEIGHT / 2, 0] }
                    initialSnap = { 1 }
                    overdragResistanceFactor = { 8 }
                    renderContent = { this.renderReactionsPickerContent }
                    renderHeader = { this.reactionsPickerBottomSheetHeader }
                    enabledInnerScrolling = { true }

                    // listening to both events, as `closeStart` not called when half-way opened (called only when completely open),
                    // but we do want start the transition as early as possible
                    onCloseStart = { this.onReactionsPickerBottomSheetClose }
                    onCloseEnd = { this.onReactionsPickerBottomSheetClose }
                />
</Modal>

The sheet can be opened by setting isPresentingReactionsPickerBottomsheet to true, while closing it be listening the Modal’s callbacks: onBackButtonPress and onBackdropPress and running the same logic, but with false:

private onReactionsPickerBottomSheetClose = () => {
        this.setState({ isPresentingReactionsPickerBottomsheet: false })
    }
Abdulaev commented 4 years ago

@mstaicu sorry missed your comment! Here it is:

<Modal
                useNativeDriver = { true }
                style = { styles.modal }
                isVisible = { this.state.isPresentingReactionsPickerBottomsheet }
                onBackButtonPress = { this.onReactionsPickerBottomSheetClose }
                onBackdropPress = { this.onReactionsPickerBottomSheetClose }
            >
                <BottomSheet
                    ref = { this.onGetReactionsPickerBottomSheetRef }
                    snapPoints = { [USERS_REACTIONS_BOTTOM_SHEET_INITIAL_HEIGHT, USERS_REACTIONS_BOTTOM_SHEET_INITIAL_HEIGHT / 2, 0] }
                    initialSnap = { 1 }
                    overdragResistanceFactor = { 8 }
                    renderContent = { this.renderReactionsPickerContent }
                    renderHeader = { this.reactionsPickerBottomSheetHeader }
                    enabledInnerScrolling = { true }

                    // listening to both events, as `closeStart` not called when half-way opened (called only when completely open),
                    // but we do want start the transition as early as possible
                    onCloseStart = { this.onReactionsPickerBottomSheetClose }
                    onCloseEnd = { this.onReactionsPickerBottomSheetClose }
                />
</Modal>

The sheet can be opened by setting isPresentingReactionsPickerBottomsheet to true, while closing it be listening the Modal’s callbacks: onBackButtonPress and onBackdropPress and running the same logic, but with false:

private onReactionsPickerBottomSheetClose = () => {
        this.setState({ isPresentingReactionsPickerBottomsheet: false })
    }

Is it swipable with modal? I'm using react-native-modal with react-native-reanimated-bottom-sheet and its not!

mstaicu commented 4 years ago

@Abdulaev, as far as I know, react-native-modal is a wrapper around the Modal component exposed by react-native, which seeks to add missing functionality. It does not solve any of the existing issues regarding the usage of the bottom sheet in the modal. The main issue, for me at least, is the fact that the fix introduced in this pull request does not work when the bottom sheet is used inside a modal which is then rendered on a screen that is rendering lots of times. The result is that it auto dismisses the modal that contains the bottom sheet. I will respond to this thread if I have any updates regarding fixes or workarounds

julianoddreis commented 4 years ago

I migrated to: https://github.com/jeremybarbet/react-native-modalize

ashumantoo commented 4 years ago

@zmnv thanks – no, I mean https://github.com/react-native-community/react-native-modal

by wrapping BottomSheet by Modal - react-native-reanimated-bottom-sheet gesture is not working like dragging and droping.

trescomasdev commented 4 years ago

react-native-portalize the key guys!!!! Just wrap the tabnavigation in the Host component and after any place in the application wrap your bottomsheet component in a Portal component. Works like hell!!!!

wtfabio commented 2 years ago

react-native-portalize the key guys!!!! Just wrap the tabnavigation in the Host component and after any place in the application wrap your bottomsheet component in a Portal component. Works like hell!!!!

Works beautifully. Thank you!