cssreact-nativeview

white space between Views React-Native


I've designed a layout for my React Native application that includes several components. Among these are a header, a FlatList that displays dates horizontally, and a gray View containing various components related to activities. However, I'm encountering an issue where there's a significant amount of white space between the FlatList and the gray View. My objective is to minimize this white space and bring the gray View closer to the FlatList, ensuring a more visually appealing layout. And the last problem is with the 2 cards you can see that are not aligned correctly.

import React, { useState } from "react";
import {
    FlatList,
    Dimensions,
    Alert,
    TouchableOpacity,
    Image,
    View,
    StyleSheet,
} from "react-native";
import { Text, Button, Icon } from "@rneui/base";
import { SafeAreaView } from "react-native-safe-area-context";
import OrarioCheckIn from "@/OrarioCheckIn";
import OrarioCheckOut from "@/OrarioCheckOut";
import UserCheckIn from "@/UserCheckIn";
import UserCheckOut from "@/UserCheckOut";
import { ScrollView } from "react-native-gesture-handler";

const { width } = Dimensions.get("window");
const daysToShow = 4;
const margin = 10;
const itemWidth = (width - margin * (daysToShow * 2)) / daysToShow;
const totalDays = 30;

export default function Home() {
    const today = new Date();
    const currentDate = today.toLocaleDateString("it-IT", {
        weekday: "short",
        day: "2-digit",
        month: "short",
    });
    const formatTime = (time: number) => {
        return time < 10 ? `0${time}` : `${time}`;
    };

    const currentTime = `${formatTime(today.getHours())}:${formatTime(
        today.getMinutes()
    )}`;
    const dates = Array.from({ length: totalDays }, (_, i) => {
        const d = new Date();
        d.setDate(today.getDate() - i);
        return d;
    }).reverse();

    const getItemLayout = (data: any, index: number) => ({
        length: itemWidth + margin * 2,
        offset: (itemWidth + margin * 2) * index,
        index,
    });

    const capitalizeFirstLetter = (string: string) => {
        return string.charAt(0).toUpperCase() + string.slice(1);
    };

    const [showCheckIn, setShowCheckIn] = useState(false);
    const [showCheckOut, setShowCheckOut] = useState(false);
    const [checkInTime, setCheckInTime] = useState(currentTime);
    const [checkOutTime, setCheckOutTime] = useState("");

    const handleCheckInClick = () => {
        const now = new Date();
        const currentCheckInTime = `${formatTime(now.getHours())}:${formatTime(
            now.getMinutes()
        )}`;
        setCheckInTime(currentCheckInTime);
        setShowCheckIn(true);
        setShowCheckOut(false);
    };

    const handleCheckOutClick = () => {
        const now = new Date();
        const currentCheckOutTime = `${formatTime(now.getHours())}:${formatTime(
            now.getMinutes()
        )}`;
        setCheckOutTime(currentCheckOutTime);
        setShowCheckOut(true);
    };

    return (
        <SafeAreaView style={styles.container}>
            <View style={styles.header}>
                <TouchableOpacity
                    onPress={() => Alert.alert("Profile button pressed")}
                >
                    <Image
                        source={{
                            uri: "https://cdn-icons-png.flaticon.com/512/0/14.png",
                        }}
                        style={styles.profileImage}
                    />
                </TouchableOpacity>
                <TouchableOpacity
                    onPress={() => Alert.alert("Notification button pressed")}
                >
                    <Icon
                        name="notifications"
                        color="black"
                        style={styles.notificationIcon}
                    />
                </TouchableOpacity>
            </View>
            <FlatList
                style={styles.flatList}
                contentContainerStyle={styles.flatListContent}
                data={dates}
                horizontal
                pagingEnabled
                showsHorizontalScrollIndicator={false}
                renderItem={({ item: date }) => (
                    <TouchableOpacity
                        onPress={() =>
                            Alert.alert(
                                `Hai selezionato il giorno ${date.getDate()}`
                            )
                        }
                        style={styles.dateItem}
                    >
                        <Text style={styles.dateNumber}>{date.getDate()}</Text>
                        <Text style={styles.dateWeekday}>
                            {capitalizeFirstLetter(
                                date.toLocaleDateString("it-IT", {
                                    weekday: "short",
                                })
                            )}
                        </Text>
                    </TouchableOpacity>
                )}
                keyExtractor={(item, index) => index.toString()}
                initialScrollIndex={totalDays - daysToShow}
                getItemLayout={getItemLayout}
            />
            <View style={styles.wrapper}>
                <View style={styles.contentWrapper}>
                    <View style={styles.activityContainer}>
                        <Text style={styles.heading}>Oggi</Text>
                        <View style={styles.activityRow}>
                            <OrarioCheckIn />
                            <OrarioCheckOut />
                        </View>
                    </View>
                    <Text style={styles.heading}>Le tue attività</Text>
                    <View style={styles.userActivitiesContainer}>
                        <ScrollView style={styles.userActivities}>
                            {showCheckIn && (
                                <UserCheckIn
                                    orario={checkInTime}
                                    data={currentDate}
                                />
                            )}
                            {showCheckOut && (
                                <UserCheckOut
                                    orario={checkOutTime}
                                    data={currentDate}
                                />
                            )}
                            {!showCheckIn && !showCheckOut && (
                                <Text style={styles.noActivityText}>
                                    Non hai effettuato il check-in o il
                                    check-out
                                </Text>
                            )}
                        </ScrollView>
                    </View>
                    <Button
                        title={
                            showCheckIn
                                ? "Scorri per il Check Out"
                                : "Scorri per il Check In"
                        }
                        radius="lg"
                        buttonStyle={styles.actionButton}
                        titleStyle={styles.actionButtonText}
                        onPress={
                            showCheckIn
                                ? handleCheckOutClick
                                : handleCheckInClick
                        }
                    />
                </View>
            </View>
        </SafeAreaView>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: "white",
    },
    header: {
        flexDirection: "row",
        justifyContent: "space-between",
        padding: 15,
    },
    profileImage: {
        width: 50,
        height: 50,
        borderRadius: 25,
    },
    notificationIcon: {
        fontSize: 24,
    },
    wrapper: {
        flex: 1,
        backgroundColor: "#F9F9F9",
        borderTopLeftRadius: 20,
        borderTopRightRadius: 20,
        paddingTop: 20,
    },
    flatList: {
        marginBottom: 10,
    },
    flatListContent: {
        paddingBottom: 20,
    },
    dateItem: {
        width: itemWidth,
        height: 80,
        borderWidth: 1,
        borderColor: "lightgrey",
        backgroundColor: "white",
        justifyContent: "center",
        alignItems: "center",
        margin: margin,
        borderRadius: 10,
    },
    dateNumber: {
        fontFamily: "KumbhSans-Bold",
        fontSize: 24,
    },
    dateWeekday: {
        fontFamily: "KumbhSans-Regular",
        fontSize: 16,
    },
    contentWrapper: {
        paddingHorizontal: 10,
        flex: 1,
    },
    activityContainer: {
        flexDirection: "row",
        justifyContent: "space-between",
        padding: 15,
    },
    heading: {
        fontFamily: "KumbhSans-Bold",
        fontSize: 20,
        marginLeft: 15,
        marginBottom: 10,
    },
    activityRow: {
        flexDirection: "row",
    },
    userActivitiesContainer: {
        flex: 1,
        marginBottom: 10,
    },
    userActivities: {
        flex: 1,
    },
    noActivityText: {
        textAlign: "center",
        fontFamily: "KumbhSans-Bold",
        color: "gray",
        fontSize: 15,
        marginTop: 10,
    },
    actionButton: {
        height: 50,
        backgroundColor: "#3B82F6",
        marginBottom: 20,
        marginHorizontal: 20,
    },
    actionButtonText: {
        fontFamily: "KumbhSans-Regular",
        fontSize: 20,
    },
});

If needed I will provide the components code. Thanks.


Solution

  • In your styles code you have:

    wrapper: {
        flex: 1,
        backgroundColor: "#F9F9F9",
        borderTopLeftRadius: 20,
        borderTopRightRadius: 20,
        paddingTop: 20,
    },
    flatList: {
        marginBottom: 10,
    },
    flatListContent: {
        paddingBottom: 20,
    },
    

    So what happens here is your flatList has paddingBottom of 20px and marginBottom set to 10px. Also you set paddingTop of your wrapper to 20px, so in total you have 50px of white space. Plese try to lower these values to reduce the white space between flatList and wrapper.