Gasture Scroll Page

 import { FlatList, Image, Pressable, Dimensions, StyleSheet, Text, View, useWindowDimensions, ScrollView, StatusBar, Alert } from 'react-native'

import React, { useEffect, useState } from 'react'
import Styles from '../../Styles/GlobalCss/Styles'
import Icon from 'react-native-vector-icons/FontAwesome'
import Icons from 'react-native-vector-icons/FontAwesome5'
import Color from '../../assets/color'
import size from '../../assets/size'
import WebApi from '../../Utils/WebApi'
import Header from '../../Components/Header'
import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps';
import { TextInput } from '../../Components'
import {
    GestureHandlerRootView,
    PanGestureHandler,
    TouchableOpacity,
} from 'react-native-gesture-handler';
import Animated, {
    useAnimatedGestureHandler,
    useAnimatedStyle,
    useSharedValue,
    withSpring,
    WithSpringConfig,
} from 'react-native-reanimated';



// type SheetPositions = 'minimised' | 'maximised' | 'expanded';

const window = Dimensions.get('window');
const screen = Dimensions.get('screen');

const NAV_HEIGHT = 48;

const Sheet = (props) => {
    const [dimensions, setDimensions] = useState({ window, screen });
    const { width, height } = useWindowDimensions();
    const [selectTab, setSelectTab] = useState('0')
    const [myPin, setMyPin] = useState([
        { type: 'Home' }, { type: 'Office' }, { type: 'Apartment' }, { type: 'Apartment' }
    ])
    const [Tab, setTab] = useState([
        { type: 'Home' }, { type: 'Bookings' }, { type: 'Wallet' }, { type: 'Profile' }
    ])

    useEffect(() => {
        // Watch for screen size changes and update the dimensions
        const subscription = Dimensions.addEventListener(
            'change',
            ({ window, screen }) => {
                setDimensions({ window, screen });
            }
        );
        return () => subscription?.remove();
    });

    // Fixed values (for snap positions)
    const minHeight = props.minHeight || 200;
    const maxHeight = props.maxHeight || dimensions.screen.height;
    const expandedHeight = props.expandedHeight || dimensions.screen.height * 0.6;

    // Animated values
    const position = useSharedValue('minimised');
    const sheetHeight = useSharedValue(-minHeight);
    const navHeight = useSharedValue(0);

    const springConfig = {
        damping: 50,
        mass: 0.3,
        stiffness: 120,
        overshootClamping: true,
        restSpeedThreshold: 0.3,
        restDisplacementThreshold: 0.3,
    };

    const DRAG_BUFFER = 40;

    const onGestureEvent = useAnimatedGestureHandler({
        // Set the context value to the sheet's current height value
        onStart: (_ev, ctx) => {
            ctx.offsetY = sheetHeight.value;
        },
        // Update the sheet's height value based on the gesture
        onActive: (ev, ctx) => {
            sheetHeight.value = ctx.offsetY + ev.translationY;
        },
        // Snap the sheet to the correct position once the gesture ends
        onEnd: () => {
            // Snap to expanded position if the sheet is dragged up from minimised position
            // or dragged down from maximised position
            const shouldExpand =
                (position.value === 'maximised' &&
                    -sheetHeight.value < maxHeight - DRAG_BUFFER) ||
                (position.value === 'minimised' &&
                    -sheetHeight.value > minHeight + DRAG_BUFFER);

            // Snap to minimised position if the sheet is dragged down from expanded position
            const shouldMinimise =
                position.value === 'expanded' &&
                -sheetHeight.value < expandedHeight - DRAG_BUFFER;

            // Snap to maximised position if the sheet is dragged up from expanded position
            const shouldMaximise =
                position.value === 'expanded' &&
                -sheetHeight.value > expandedHeight + DRAG_BUFFER;

            // Update the sheet's position with spring animation
            if (shouldExpand) {
                navHeight.value = withSpring(0, springConfig);
                sheetHeight.value = withSpring(-expandedHeight, springConfig);
                position.value = 'expanded';
            } else

                // if (shouldMaximise) {
                //     navHeight.value = withSpring(NAV_HEIGHT + 10, springConfig);
                //     sheetHeight.value = withSpring(-maxHeight, springConfig);
                //     position.value = 'maximised';
                // } else

                if (shouldMinimise) {
                    navHeight.value = withSpring(0, springConfig);
                    sheetHeight.value = withSpring(-minHeight, springConfig);
                    position.value = 'minimised';
                } else {
                    sheetHeight.value = withSpring(
                        position.value === 'expanded'
                            ? -expandedHeight
                            : position.value === 'maximised'
                                ? -maxHeight
                                : -minHeight,
                        springConfig
                    );
                }
        },
    });

    const sheetHeightAnimatedStyle = useAnimatedStyle(() => ({
        height: -sheetHeight.value+80,
    }));

    const sheetContentAnimatedStyle = useAnimatedStyle(() => ({
        paddingBottom: position.value === 'maximised' ? 180 : 0,
        paddingTop: position.value === 'maximised' ? 40 : 20,
        paddingHorizontal: 20,
    }));

    const sheetNavigationAnimatedStyle = useAnimatedStyle(() => ({
        height: navHeight.value,
        overflow: 'hidden',
    }));

    return (
        <View style={styles.container}>
            <StatusBar
                backgroundColor={"transparent"}
                translucent={true}
                barStyle={'dark-content'}
            />

            <GestureHandlerRootView style={{ flex: 1 }} >

                <View style={[{ width: '100%', }]}>
                    <View style={[Styles.flexRow, Styles.justifyFE, { backgroundColor: 'transparent', position: 'absolute', top: 150, zIndex: 999, width: '100%' }]}>
                        <View style={[Styles.round, Styles.fullCenter, { marginRight: 16 }]}>
                            <Icon name="search" color={Color.colorPrimary} size={20} />
                        </View>
                        <View style={[Styles.round, Styles.fullCenter, { marginRight: 16 }]}>
                            <Icons name="badge-percent" color={Color.colorPrimary} size={20} />
                        </View>
                        <View style={[Styles.round, Styles.fullCenter, { marginRight: 16 }]}>
                            <Icon name="bell" color={Color.colorPrimary} size={20} />
                            <View style={[{ position: 'absolute', top: 10, right: 14, backgroundColor: Color.colorRed, height: 7, width: 7, borderRadius: 10 }]} />
                        </View>
                    </View>
                    <MapView
                        // provider={PROVIDER_GOOGLE} // remove if not using Google Maps
                        style={[{ height: height - sheetHeight.value, width: '100%', marginTop: 0 }]}
                        region={{
                            latitude: 28.508451,
                            longitude: 77.031173,
                            latitudeDelta: 0.015,
                            longitudeDelta: 0.0121,
                        }}
                    >
                        <Marker
                            coordinate={{
                                latitude: 28.508451,
                                longitude: 77.031173,
                            }} >
                            <View style={[Styles.fullCenter, { height: 120, width: 120, borderRadius: 70, backgroundColor: Color.colorPrimary + 55, borderWidth: 0, borderColor: Color.colorPrimary }]}>
                                <View style={[Styles.fullCenter, { height: 60, width: 60, borderRadius: 30, backgroundColor: 'pink', borderWidth: 3, borderColor: Color.white }]}>
                                    <Image source={require('../../assets/image/boy.png')} style={[{ height: 40, width: 40, }]} />
                                </View>
                            </View>
                        </Marker>
                    </MapView>

                    <View style={[{ position: 'absolute', bottom: 0, width: '100%', paddingBottom: 30 }]}>
                        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
                            {myPin?.map((item, index) =>
                                <View style={[styles.savePin]}>
                                    <Icons name="map-marker-alt" color={Color.colorPrimary} />
                                    <Text style={[Styles.textBlack, { fontWeight: '500', paddingHorizontal: 10 }]}>{item.type}</Text>
                                </View>
                            )}
                        </ScrollView>
                        <View style={[styles.pointer]}>
                            <Icons name="location" color={Color.white} size={15} />
                        </View>
                    </View>
                </View>
                <PanGestureHandler onGestureEvent={onGestureEvent}>
                    <Animated.View style={[sheetHeightAnimatedStyle, styles.sheet]}>
                        <View style={styles.handleContainer}>
                            <View style={styles.handle} />
                        </View>
                        <Animated.View style={{ flex: 1 }}>
                            <>
                                <ScrollView style={[{ flex: 1 }]}>
                                    <View style={[styles.scrollview, {}]}>
                                        <View>
                                            <TextInput
                                                placeholder="Where would you go?"
                                                pin
                                            />
                                        </View>
                                        <View style={[Styles.flexRow, Styles.alignC, Styles.paddingV20, Styles.justifySA]}>
                                            {Tab?.map((item, index) =>
                                                <Pressable
                                                    onPress={() => setSelectTab(index)}
                                                    style={[Styles.List, styles.bottomTab, { backgroundColor: selectTab == index ? Color.colorPrimaryL : Color.white, }]}>
                                                    <Icons name="map-marker-alt" color={selectTab == index ? Color.colorPrimary : Color.colorHintLBlack} />
                                                    <Text style={[Styles.textBlack, { fontWeight: '500', paddingHorizontal: 5 }]}>{item.type}</Text>
                                                </Pressable>
                                            )}
                                        </View>
                                    </View>
                                </ScrollView>
                            </>
                        </Animated.View>
                    </Animated.View>
                </PanGestureHandler>
            </GestureHandlerRootView>
        </View>
    );
};

const styles = StyleSheet.create({
    container: {
        position: 'absolute',
        bottom: 0,
        left: 0,
        right: 0,
    },
    sheet: {
        justifyContent: 'flex-start',
        backgroundColor: '#FFFFFF',
        borderTopLeftRadius: 20,
        borderTopRightRadius: 20,
        minHeight: 80,
        shadowColor: '#000',
        shadowOffset: {
            width: 0,
            height: -2,
        },
        shadowOpacity: 0.23,
        shadowRadius: 2.62,
        elevation: 4,
    },
    handleContainer: {
        alignItems: 'center',
        justifyContent: 'center',
        paddingTop: 10,
    },
    handle: {
        width: '15%',
        height: 4,
        borderRadius: 8,
        backgroundColor: '#CCCCCC',
    },
    closeButton: {
        width: NAV_HEIGHT,
        height: NAV_HEIGHT,
        borderRadius: NAV_HEIGHT,
        alignItems: 'center',
        justifyContent: 'center',
        alignSelf: 'flex-start',
        marginBottom: 10,
    },
    bottomTab: {
        paddingVertical: 8,
        borderRadius: 10,
        paddingHorizontal: 10,
        marginHorizontal: 2,
        borderColor: Color.colorPrimary,
    },
    scrollview: {
        ...Styles.alignC,
        ...Styles.width100,
        borderTopLeftRadius: 30,
        borderTopRightRadius: 30,
        backgroundColor: Color.white,
        flex: 1,
    },
    pointer: {
        ...Styles.Icon,
        ...Styles.fullCenter,
        borderRadius: 20,
        position: 'absolute',
        top: -60, right: 20,
        backgroundColor: Color.colorPrimary
    },
    savePin: {
        ...Styles.List,
        ...Styles.Compborder1,
        backgroundColor: Color.white,
        marginHorizontal: 5,
        paddingVertical: 10,
        borderRadius: 30,
        paddingHorizontal: 10,
        borderColor: Color.colorPrimary,
        paddingLeft: 15
    }
});

export default Sheet;
SHARE

Milan Tomic

Hi. I’m Designer of Blog Magic. I’m CEO/Founder of ThemeXpose. I’m Creative Art Director, Web Designer, UI/UX Designer, Interaction Designer, Industrial Designer, Web Developer, Business Enthusiast, StartUp Enthusiast, Speaker, Writer and Photographer. Inspired to make things looks better.

  • Image
  • Image
  • Image
  • Image
  • Image
    Blogger Comment
    Facebook Comment

0 comments:

Post a Comment