Deniss
Deniss

Reputation: 93

SafeAreaView is not working inside modal screen

I have a modal screen (presentation: 'modal') and inside it I have a scrollable FlatList. The problem is that I cannot achieve spacing at the bottom together with transparent bottom safe area. I use SafeAreaView from react-native-safe-area-context.

I have tried many solutions and non actually worked. So far I have tried:

  1. Wrapping screen content with SafeAreaView;
  2. Wrapping FlatList with SafeAreaView;
  3. Adding style={ { paddingBottom: 50 } } to FlatList;
  4. Adding contentContainerStyle={ { paddingBottom: 50 } } to FlatList;
  5. Adding ListFooterComponent={ <SafeAreaView edges={ ['bottom'] } forceInset={ { bottom: 'always' } } /> } to FlatList;
  6. Also tried using ScrollView instead of FlatList.

Screenshots:

I either have a scrollbar to the bottom of the screen, but listing has correct spacing: enter image description here

OR

have a margin at the bottom and then the scrollbar looks good (it scrolls to the red line): enter image description here

If I compare it to native iOS applications, they behave exactly how I want- scrollbar is scrolling to the safe area and bottom are is transparent when I scroll: enter image description here

Screen component:

return (
        <SafeAreaView forceInset={ { top: 'never', bottom: 'always' } }>
            <View style={ styles.container }>
                <FlatList
                    style={ { marginBottom: 0 } }
                    // showsVerticalScrollIndicator={ false }
                    // contentInsetAdjustmentBehavior="automatic"
                    numColumns={ 4 }
                    // ListFooterComponent={ <SafeAreaView edges={ ['bottom'] } mode="margin" forceInset={ { bottom: 'always' } } /> }
                    // contentInset={ { bottom: 1 } }
                    // contentContainerStyle={ [{paddingBottom: 30 }] }
                    data={ [] }
                    renderItem={ ({ item }) => {
                        return renderCategory(item);
                    } }
                />

            </View>
        </SafeAreaView>
    );

Navigator component:

return (
        <Stack.Navigator initialRouteName="DashboardStack">
            <Stack.Group screenOptions={ {
                headerLargeTitle: false,
                headerShown: true,
                headerShadowVisible: false,
                presentation: 'modal'
            } }>
                <Stack.Screen
                    name="CategoryModal"
                    component={ CategoryModal }
                    options={ {
                        title: 'Categories',
                        contentStyle: {
                            backgroundColor: '#ffffff'
                        }
                    } }
                />
            </Stack.Group>
        </Stack.Navigator>
    );

Upvotes: 4

Views: 2489

Answers (3)

Hussnain Hashmi
Hussnain Hashmi

Reputation: 111

I've used safeAreaview from react-native in my app and it is working fine in modal. for example

import { Modal, View, Text, KeyboardAvoidingView,
Platform, SafeAreaView, } from "react-native";

    <Modal
  visible={visible}
  transparent={true}
  animationType="slide"
  onRequestClose={handleNo}
  style={{flex:1}}
>
    <SafeAreaView style={Styles.modalContainer}>
      <View style={Styles.modalContent}>
        <Text style={Styles.modalTitle}>{title}</Text>
        {text ? <Text style={Styles.modalDescription}>{text}</Text> : null}

        {children}
        <View style={Styles.bottomButtonsStyle}>
          <CustomButton
            label={buttonTextNo ? buttonTextNo : Strings.cancel}
            onPress={() => {
              if (handleNo) {
                handleNo();
              }
            }}
            style={{ marginHorizontal: widthPercentageToDP(1) }}
            type={ButtonType.CANCEL}
          />

          {/* Conditionally render the Yes button */}
          {(handleYes) && (
            <CustomButton
              label={buttonTextYes ? buttonTextYes : Strings.submit}
              onPress={() => {
                if (handleYes) {
                  handleYes();
                }
              }}
              style={{ marginHorizontal: widthPercentageToDP(1) }}
            />
          )}
        </View>
      </View>
    </SafeAreaView>
</Modal>

styles:

StyleSheet.create({
modalContainer: {
  flex: 1,
  justifyContent: centered ? "center" : "flex-end",
  backgroundColor: ThemeColors.transparentBlackShade, // Semi-transparent background
},
modalContent: {
  backgroundColor: theme.colors.card,
  padding: wp("5%"),
  borderRadius: 30,
  marginHorizontal: Dimensions.horizontalPadding,
},
modalTitle: {
  fontSize: wp("5%"),
  fontWeight: "bold",
  color: theme.colors.text,
  paddingVertical: hp(1),
},
modalDescription: {
  fontSize: wp("4%"),
  color: theme.colors.text,
  opacity: 0.8,
  paddingVertical: hp(1),
},
modalButton: {
  paddingVertical: hp("2%"),
  borderRadius: 15,
  alignItems: "center",
  justifyContent: "center",
  marginVertical: hp("1%"),
  borderWidth: 1,
  borderColor: "#ddd",
},
yesButton: {
  backgroundColor: ThemeColors.primaryButton,
},
cancelButton: {
  backgroundColor: "#fff",
},
buttonText: {
  fontWeight: "bold",
  fontSize: wp("5%"),
},
buttonTextYes: {
  color: "#fff",
},
buttonTextNo: {
  color: "#000",
},
keyboardAvoidingContainer: {
  flex: 1,
},
scrollViewContent: {
  flexGrow: 1,
  // paddingHorizontal: Dimensions.horizontalPadding,
},
bottomButtonsStyle: {
  flexDirection: buttonOrientationHorizontal ? "row" : "column",
  minHeight: buttonOrientationHorizontal ? hp(7) : renderYes ? hp(14): hp(7),
  justifyContent: buttonOrientationHorizontal ? "center" : "flex-end",
  marginTop: hp(1),
},

});

Upvotes: 0

Jeffrey
Jeffrey

Reputation: 1

Add style={{ flex: 1}} to SafeAreaView

Upvotes: -1

user2316154
user2316154

Reputation: 334

Ran into this today and came across this question.

You may need to wrap your modal in its own SafeAreaContextProvider.

See the doc here: https://www.npmjs.com/package/react-native-safe-area-context#safeareaprovider

You should add SafeAreaProvider in your app root component. You may need to add it in other places like the root of modals and routes when using react-native-screens.

In my case, I was using Portal from react-native-paper, and adding a SafeContextProvider nested directly under the Portal solved my problem. In your example wrapping the component that the Stack.Screen serves might have done the trick.

Upvotes: 0

Related Questions