Quantcast
Channel: Active questions tagged react-native+typescript - Stack Overflow
Viewing all articles
Browse latest Browse all 6290

React Native - Trying change 2 View heights with GestureHandler

$
0
0

I am trying to create Height adjustable Views with React Native for an app I am building. I keep getting stuck on this one aspect. I am trying to create two stacked Views, with a line inbetween them so they are height adjustable when dragging the line up or down, adjusting content in it as well. Image below is a representation of what I am trying to make. "Home Option 2" is default state, "Home Option 1.3 is when the slider is dragged down, and "Home Option 1.2" is opposite - slider dragged up.

With an app bar at the bottom. (I dont have it made yet)

enter image description here

Here is my code for App.tsx

import * as React from 'react';import { GestureHandlerRootView } from 'react-native-gesture-handler';import { StatusBar } from 'expo-status-bar';import { StyleSheet, TouchableOpacity, View } from 'react-native';import BottomSheet, { BottomSheetRefProps } from './components/BottomSheet';import { useCallback, useRef } from 'react';import MapView, { Marker, Geojson } from "react-native-maps";import { PROVIDER_GOOGLE } from "react-native-maps";export default function App() {  const ref = useRef<BottomSheetRefProps>(null);  const [topViewHeight, setTopViewHeight] = React.useState(0);  const onPress = useCallback(() => {    const isActive = ref?.current?.isActive();    if (isActive) {      ref?.current?.scrollTo(0);    } else {      ref?.current?.scrollTo(-200);    }  }, []);  return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.mapViewContainer}><MapView          provider={PROVIDER_GOOGLE}          showsUserLocation={true}          style={styles.mapView}          initialRegion={{            latitude: 00.00 ,            longitude: -00.00 ,            latitudeDelta: 00.00 ,            longitudeDelta: 00.00 ,          }}><Marker coordinate={{ latitude: 00.00, longitude: 00.00 }} /></MapView></View><View style={styles.container}><StatusBar style="light" /><TouchableOpacity style={styles.button} onPress={onPress} /><BottomSheet ref={ref} {...{setTopViewHeight, topViewHeight}}><View style={{ flex: 1, backgroundColor: 'orange' }} /></BottomSheet></View></GestureHandlerRootView>  );}const styles = StyleSheet.create({  container: {    flex: 1,    backgroundColor: '#111',    alignItems: 'center',    justifyContent: 'center',  },  button: {    height: 50,    borderRadius: 25,    aspectRatio: 1,    backgroundColor: 'white',    opacity: 0.6,  },  mapViewContainer: {    height: "50%",    width: "95%",    overflow: "hidden",    background: "transparent",    borderRadius: 13,  },  mapView: {    height: "100%",    width: "100%",  },});

Code for BottomSheet.tsx (Which i was using as a reference for the ideal UX)

import { Dimensions, StyleSheet, Text, View } from 'react-native';import React, { useCallback, useEffect, useImperativeHandle } from 'react';import { Gesture, GestureDetector } from 'react-native-gesture-handler';import Animated, {  Extrapolate,  interpolate,  useAnimatedStyle,  useSharedValue,  withSpring,  withTiming,} from 'react-native-reanimated';const { height: SCREEN_HEIGHT } = Dimensions.get('window');const TOP_VIEW_HEIGHT = 50;const VIEW_RESIZE = 2.5;const MAX_TRANSLATE_Y = -SCREEN_HEIGHT / VIEW_RESIZE;type BottomSheetProps = {  children?: React.ReactNode;  setTopViewHeight: (height: number) => void;  topViewHeight: number;};export type BottomSheetRefProps = {  scrollTo: (destination: number) => void;  isActive: () => boolean;};const BottomSheet = React.forwardRef<BottomSheetRefProps, BottomSheetProps>(  ({ children }, ref) => {    const translateY = useSharedValue(0);    const active = useSharedValue(false);    const scrollTo = useCallback((destination: number) => {'worklet';      active.value = destination !== 0;      translateY.value = withSpring(destination, { damping: 50 });    }, []);    const isActive = useCallback(() => {      return active.value;    }, []);    useImperativeHandle(ref, () => ({ scrollTo, isActive }), [      scrollTo,      isActive,    ]);    const context = useSharedValue({ y: 0 });    const gesture = Gesture.Pan()      .onStart(() => {        context.value = { y: translateY.value };      })      .onUpdate((event) => {        translateY.value = event.translationY + context.value.y;        translateY.value = Math.max(translateY.value, MAX_TRANSLATE_Y);        console.log(translateY.value);      })      .onEnd(() => {        if (translateY.value > -SCREEN_HEIGHT / 3) {          scrollTo(0);        } else if (translateY.value < -SCREEN_HEIGHT / 1.5) {          scrollTo(MAX_TRANSLATE_Y);        }        console.log('end: '+ translateY.value)      });    const rBottomSheetStyle = useAnimatedStyle(() => {      const borderRadius = interpolate(        translateY.value,        [MAX_TRANSLATE_Y + 50, MAX_TRANSLATE_Y],        [25, 5],        Extrapolate.CLAMP      );      return {        borderRadius,        transform: [{ translateY: translateY.value }],        maxHeight: 500,      };    });    return (<GestureDetector gesture={gesture}><Animated.View style={[styles.bottomSheetContainer, rBottomSheetStyle] }><View style={styles.line} />          {children}</Animated.View></GestureDetector>    );  });const styles = StyleSheet.create({  bottomSheetContainer: {    minHeight: SCREEN_HEIGHT - 50,    width: '100%',    backgroundColor: 'white',    position: 'relative',    top: SCREEN_HEIGHT - 500,    borderRadius: 25,  },  line: {    width: 75,    height: 4,    backgroundColor: 'grey',    alignSelf: 'center',    marginVertical: 15,    borderRadius: 2,  },});export default BottomSheet;

Viewing all articles
Browse latest Browse all 6290

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>