布局改变时的React native(监听视图位置)。

问题描述 投票:0回答:1

我想用平移响应器来监听我正在移动的视图的位置,我正在使用onLayout道具来获取宽度、高度、x和y的位置,但只有在第一次渲染时才会运行。我使用onLayout道具来获取宽度、高度、x和y位置,但它只在第一次渲染时运行。有什么好办法吗?

下面是代码。

import React, { useState, useRef } from "react";
import {
  View,
  Animated,
  PanResponder,
  Dimensions,
  StyleSheet,
} from "react-native";

const WINDOW_HEIGHT = Dimensions.get("window").height;

export default function Cropper({ photo }) {
  const [height, setHeight] = useState(WINDOW_HEIGHT / 2); // Use in future

  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event([null, { dy: pan.y }]),
      onPanResponderRelease: () => {
        pan.flattenOffset();
      },
    })
  ).current;

 const onLayout = (event) => {
    const {
      nativeEvent: { layout },
    } = event;

    // Recalculate top and buttom views' height (setNativeProps)
  };

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

  return (
    <View style={styles.container}>
      <View style={styles.blurView} />
      <Animated.View
        onLayout={(event) => onLayout(event)}
        {...panResponder.panHandlers}
        style={[
          styles.cropper,
          panStyle,
          {
            height: height,
          },
        ]}
      />
      <View style={styles.blurView} />
      <View style={styles.bottomButtonsContainer}></View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  blurView: {
    flex: 1,
    width: "100%",
    backgroundColor: "rgba(0, 0, 0, .9)",
  },
  cropper: {
    width: "100%",
    backgroundColor: "red",
  },
  bottomButtonsContainer: {
    position: "absolute",
    bottom: 0,
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    width: "100%",
    height: 120,
  },
});

我想做的是当用户移动中间视图时,得到它的位置 然后重新计算顶部和底部视图的高度。

javascript css reactjs react-native
1个回答
1
投票

如果你把onLayout作为一个道具来使用的话export default function Cropper({ photo }) { 应该是这样 export default function Cropper({ photo, onLayout }) {

否则,我同意回应中说的,你很可能需要声明 onLayout.


0
投票

看来你忘了 const 为您 onLayout.

我试过你的代码 小吃博览会 当移动红色视图时,我可以得到console.logs。


0
投票

问题:当Animated.View使用样式转换被移动时,Animated.View的OnLayout方法没有被触发。

当Animated.View使用样式转换移动时,OnLayout方法没有被触发在一个带有自定义PanResponder的Animated.View上。

解决方案(完整的代码片段在底部):

添加一个额外的监听器到 onPanResponderMove 的方法 PanResponder 可以触发任何需要使用移动事件信息的方法。

onPanResponderMove: Animated.event([null, { dy: pan.y }], {listener: ({nativeEvent}) => {onSquareMoved(nativeEvent)}}),

const onSquareMoved = (event) => {
  console.log('square moved changes')
}

为了在每次panResponder移动的时候调用一个方法,我们添加了一个listtner来监听事件并调用了 onSquareXChanged 方法--这是一个重命名的 onLayout.

我已经添加了一个完整的小吃,每次方块移动时都会调用一个方法,你可以在这里找到它。https:/snack.expo.io@m4qrspunky-soda。

它使用的代码来自一个 回答@ajthyng. 在运行你的小吃版本时,我得到的onLayout只在第一次渲染时启动,而不是在移动squre时启动。结合调试的结果和下面github问题的回复。https:/github.comfacebookreact-nativeissues28775。在Animated.View中,当风格转换值被改变时,onLayout似乎不会被触发。

如果你的组件在 Animated.View 是一个比较复杂的动画,或者所需的动画计算量比较大,你可能会遇到性能问题。如果你有兴趣在不损失性能的情况下添加更复杂的动画效果,我建议你看看Reanimated 2库,它目前还在Alpha.该库允许你声明动画逻辑,随后将在自己的线程上执行,因为它利用了worklet功能,允许在自己的线程上运行动画逻辑,同时保持60 fps。

William Candillon有一个很好的视频,通过一个类似于上面问题中的点心的例子来探索新的库的语法。https:/www.youtube.comwatch?time_continue=471&v=e5ALKoP1m-k&feature=emb_title。

如果还有什么关于这方面的问题,请告诉我。

完整的工作代码示例。

import React, { useState, useRef } from "react";
import {
  View,
  Animated,
  PanResponder,
  Dimensions,
  StyleSheet,
} from "react-native";

const WINDOW_HEIGHT = Dimensions.get("window").height;

export default function Cropper({ photo }) {
  const [height, setHeight] = useState(WINDOW_HEIGHT / 2); // Use in future

  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event([null, { dy: pan.y }],
        {listener: ({nativeEvent}) => onSquareMoved(nativeEvent)}}),
      onPanResponderRelease: () => {
        pan.flattenOffset();
      },
    })
  ).current;

  const onSquareMoved = (event) => {
    console.log('square was moved')
  }

  return (
    <View style={styles.container}>
      <View style={styles.blurView} />
      <Animated.View
        onLayout={(event) => onLayout(event)}
        {...panResponder.panHandlers}
        style={[
          styles.cropper,
          panStyle,
          {
            height: height,
          },
        ]}
      />
      <View style={styles.blurView} />
      <View style={styles.bottomButtonsContainer}></View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  blurView: {
    flex: 1,
    width: "100%",
    backgroundColor: "rgba(0, 0, 0, .9)",
  },
  cropper: {
    width: "100%",
    backgroundColor: "red",
  },
  bottomButtonsContainer: {
    position: "absolute",
    bottom: 0,
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    width: "100%",
    height: 120,
  },
});
© www.soinside.com 2019 - 2024. All rights reserved.