PanResponder для изменения значения карты Y и проблема выхода за пределы экрана - PullRequest
0 голосов
/ 11 июля 2020

Я новичок в React-native Animation API и PanResponder API. Я хочу создать пользовательский интерфейс клонирования карт Google и анимацию карты, которая отображается после результатов. Я хочу создать карточку, и когда пользователь проведет пальцем вверх, карточка, которую вы дойдете до верхней части экрана, и когда пользователь проведет пальцем вниз, карточка должна измениться в размере до исходного положения. Демонстрация карт Google, которых я хочу достичь

Я реализовал часть кода для этого, но я сталкиваюсь с проблемой, например, когда карта выходит за пределы экрана в верхнем направлении (смахивание вверх после того, как карта достигнет верхнего положения). Иногда смахивание вниз работает, но не всегда.

Моя демонстрация

Expo Snack Link

Прил. js

import React, { useEffect, useState } from "react";
import {
  SafeAreaView,
  View,
  Text,
  Dimensions,
  PanResponder,
  Animated,
} from "react-native";
import { Searchbar, FAB } from "react-native-paper";
import MapView from "react-native-maps";
import * as Location from "expo-location";


const SCREEN_HEIGHT = Dimensions.get("window").height;
const SCREEN_WIDTH = Dimensions.get("window").width;

const App = () => {
  

  const [latitute, setLatitute] = useState(0);
  const [longitute, setLongitute] = useState(0);
  const [isLoading, setIsLoading] = useState(true);


  const pan = useState(
    new Animated.ValueXY({ x: 0, y: SCREEN_HEIGHT - 200 })
  )[0];


  const panResponder = useState(
    PanResponder.create({
      onMoveShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        pan.extractOffset();
        return true;
      },
      onPanResponderMove: (e, gestureState) => {
        pan.setValue({ x: 0, y: gestureState.dy });
      },
      onPanResponderRelease: (e, gestureState) => {
        
        if (gestureState.moveY > SCREEN_HEIGHT - 200) {
          Animated.spring(pan.y, {
            toValue: 0,
            tension: 1,
            useNativeDriver: true,
          }).start();
        } else if (gestureState.moveY < 200) {
          Animated.spring(pan.y, {
            toValue: 0,
            tension: 1,
            useNativeDriver: true,
          }).start();
        } else if (gestureState.dy < 0) {
          Animated.spring(pan.y, {
            toValue: -SCREEN_HEIGHT + 200,
            tension: 1,
            useNativeDriver: true,
          }).start();
        } else if (gestureState.dy > 0) {
          Animated.spring(pan.y, {
            toValue: SCREEN_HEIGHT - 200,
            tension: 1,
            useNativeDriver: true,
          }).start();
        }
      },
    })
  )[0];

  const animatedHeight = {
    transform: pan.getTranslateTransform(),
  };

  useEffect(() => {
    (async () => {
      let { status } = await Location.requestPermissionsAsync();

      let location = await Location.getCurrentPositionAsync({});
      console.log(location);
      setLatitute(location.coords.latitude);
      setLongitute(location.coords.longitude);
      setIsLoading(false);
    })();
  }, []);

  return (
    <SafeAreaView
      style={{
        display: "flex",
        flex: 1,
      }}
    >
      {!isLoading && (
        <View>
          <MapView
            style={{ width: SCREEN_WIDTH, height: SCREEN_HEIGHT }}
            showsUserLocation
            initialRegion={{
              latitude: latitute,
              longitude: longitute,
              latitudeDelta: 0.01,
              longitudeDelta: 0.01,
            }}
          />

          <Searchbar
            placeholder="Search"
            style={{
              position: "absolute",
              top: 10,
              margin: 10,
            }}
            
            icon="menu"
            onIconPress={() => {}}
          />

          <FAB
            style={{
              position: "absolute",
              top: SCREEN_HEIGHT * 0.8,
              left: SCREEN_WIDTH * 0.8,
            }}
            icon="plus"
            onPress={() => console.log("Pressed")}
          />

          <Animated.View
            style={[
              animatedHeight,
              {
                position: "absolute",
                right: 0,
                left: 0,
                width: SCREEN_WIDTH,
                height: SCREEN_HEIGHT,
                backgroundColor: "#0af",
                borderTopLeftRadius: 25,
                borderTopRightRadius: 25,
                zIndex: 10,
              },
            ]}
            {...panResponder.panHandlers}
          >
            <View>
              <Text>Hi</Text>
            </View>
          </Animated.View>
        </View>
      )}
    </SafeAreaView>
  );
};

export default App;


1 Ответ

1 голос
/ 15 июля 2020

, если вы хотите создать нижний лист, вы можете использовать react-native-bottomomsheet-reanimated

yarn add react-native-bottomsheet-reanimated
import React, { useEffect, useState } from "react";
import {
  SafeAreaView,
  View,
  Text,
  Dimensions,
  PanResponder,
  Animated,
  StyleSheet
} from "react-native";
import { Searchbar, FAB } from "react-native-paper";
import MapView from "react-native-maps";
import * as Location from "expo-location";
import BottomSheet from "react-native-bottomsheet-reanimated";



const SCREEN_HEIGHT = Dimensions.get("window").height;
const SCREEN_WIDTH = Dimensions.get("window").width;

const App = () => {
  

  const [latitute, setLatitute] = useState(0);
  const [longitute, setLongitute] = useState(0);
  const [isLoading, setIsLoading] = useState(true);


  const pan = useState(
    new Animated.ValueXY({ x: 0, y: SCREEN_HEIGHT - 200 })
  )[0];

  useEffect(() => {
    (async () => {
      let { status } = await Location.requestPermissionsAsync();

      let location = await Location.getCurrentPositionAsync({});
      console.log(location);
      setLatitute(location.coords.latitude);
      setLongitute(location.coords.longitude);
      setIsLoading(false);
    })();
  }, []);

  return (
    <SafeAreaView
      style={{
        display: "flex",
        flex: 1,
      }}
    >
      {!isLoading && (
        <View>
          <MapView
            style={{ width: SCREEN_WIDTH, height: SCREEN_HEIGHT }}
            showsUserLocation
            initialRegion={{
              latitude: latitute,
              longitude: longitute,
              latitudeDelta: 0.01,
              longitudeDelta: 0.01,
            }}
          />

          <Searchbar
            placeholder="Search"
            style={{
              position: "absolute",
              top: 10,
              margin: 10,
            }}
            
            icon="menu"
            onIconPress={() => {}}
          />

          <FAB
            style={{
              position: "absolute",
              top: SCREEN_HEIGHT * 0.8,
              left: SCREEN_WIDTH * 0.8,
            }}
            icon="plus"
            onPress={() => console.log("Pressed")}
          />

          <BottomSheet
          bottomSheerColor="#FFFFFF"
          initialPosition={"30%"}  //200, 300
          snapPoints={["30%","100%"]}
          isBackDropDismisByPress={true}
          isRoundBorderWithTipHeader={true}
          containerStyle={{backgroundColor:"#0af"}}
          header={
            <View>
              <Text style={styles.text}>Header</Text>
            </View>
          }
          body={
            <View style={styles.body}>
              <Text>Hi</Text>
            </View>
          }
        />

        </View>
      )}
    </SafeAreaView>
  );
};


export default App;

const styles = StyleSheet.create({
  body:{
    justifyContent:"center",
    alignItems:"center"
  },
  text:{
    fontSize:20,
    fontWeight:"bold"
  }
});

введите описание изображения здесь

...