简体   繁体   English

当要设置动画的项目位于可滚动视图前面时,Panresponder 或 Animated.View 不起作用

[英]Panresponder or Animated.View doesnt work when the item to animate is in front of a scrollable view

Hey everyone:) Should be a function for a navigation avatar which sticks to the closest corner.大家好 :) 应该是 function 用于贴在最近角落的导航头像。 While coding I used a simple circle as a placeholder.在编码时,我使用了一个简单的圆圈作为占位符。 The problem is that the following code works perfectly fine when imported to another screen, but when I replace <View style={styles.circle} /> with an image <Image source={require("../assets/dude.png")} resizeMode="contain" style={{width: 180, height: 240,}}/> it doesnt work anymore?问题是以下代码在导入到另一个屏幕时可以正常工作,但是当我将<View style={styles.circle} />替换为图像<Image source={require("../assets/dude.png")} resizeMode="contain" style={{width: 180, height: 240,}}/>它不再起作用了吗? Like I can see the image, but the animations work extremely buggy and it just goes anywhere, nothing like it's supposed to do?就像我可以看到图像一样,但是动画效果非常差,而且它随处可见,不像它应该做的那样?

I tried it also with Animated.Image instead of the view and giving it all the parameters, still no change.我也尝试使用 Animated.Image 而不是视图并为其提供所有参数,但仍然没有变化。 The weird thing is that the Image works perfectly fine if I were to run this code as a screen itself, but when I import it only the circle view works, not the image?奇怪的是,如果我将此代码作为屏幕本身运行,图像工作得非常好,但是当我导入它时,只有圆形视图有效,而不是图像?

EDIT: Just found the issue: if the Animated.Image is in front of a Scrollable View, even if it isn't part of that View, it bugs.编辑:刚刚发现问题:如果 Animated.Image 位于可滚动视图的前面,即使它不是该视图的一部分,它也会出错。 If I replace the image with anything else (like a Box), it works fine, only the image bugs in that manner:) which leads me to my next question: How can I fix that?如果我用其他任何东西(比如盒子)替换图像,它工作正常,只有图像错误以这种方式:) 这导致我的下一个问题:我该如何解决这个问题?

so this is my code:所以这是我的代码:

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

export default class Avatar extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      pan: new Animated.ValueXY(),
      screenMeasurements: {
        width: Screen.width / 2,
        height: Screen.height / 2,
      },
    };

    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,

      onPanResponderGrant: () => {
        this.state.pan.setOffset({
          x: this.state.pan.x._value,
          y: this.state.pan.y._value,
        });
      },

      onPanResponderMove: Animated.event([
        null,
        {
          dx: this.state.pan.x,
          dy: this.state.pan.y,
        },
      ]),

      onPanResponderRelease: (e, gesture) => {
        if (this.whichField(gesture) == 1) {
          console.log("top left");
          this.state.pan.flattenOffset();
          Animated.spring(this.state.pan, {
            toValue: {
              x: (Screen.width * 0.5 - 90) * -1,
              y: (Screen.height * 0.5 - 120) * -1,
            },
          }).start();
        } else if (this.whichField(gesture) == 2) {
          console.log("top right");
          this.state.pan.flattenOffset();
          Animated.spring(this.state.pan, {
            toValue: {
              x: Screen.width * 0.5 - 90,
              y: (Screen.height * 0.5 - 120) * -1,
            },
          }).start();
        } else if (this.whichField(gesture) == 3) {
          console.log("bottom left");
          this.state.pan.flattenOffset();
          Animated.spring(this.state.pan, {
            toValue: {
              x: (Screen.width * 0.5 - 90) * -1,
              y: Screen.height * 0.5 - 150,
            },
          }).start();
        } else {
          console.log("bottom right");
          this.state.pan.flattenOffset();
          Animated.spring(this.state.pan, {
            toValue: {
              x: Screen.width * 0.5 - 90,
              y: Screen.height * 0.5 - 150,
            },
          }).start();
        }
      },
    });
  }

  whichField(gesture) {
    var sm = this.state.screenMeasurements;
    let field;
    {
      gesture.moveY < sm.height && gesture.moveX < sm.width
        ? (field = 1)
        : gesture.moveY < sm.height && gesture.moveX > sm.width
        ? (field = 2)
        : gesture.moveY > sm.height && gesture.moveX < sm.width
        ? (field = 3)
        : (field = 4);
    }

    return field;
  }

  render() {
    return (
      <View style={styles.draggableContainer}>
        <Animated.View
          style={[this.state.pan.getLayout()]}
          {...this.panResponder.panHandlers}
        >
          <View style={styles.circle} />
        </Animated.View>
      </View>
    );
  }
}

let Screen = Dimensions.get("screen");

let CIRCLE_RADIUS = 45;
const styles = StyleSheet.create({
  text: {
    marginTop: 25,
    marginLeft: 5,
    marginRight: 5,
    textAlign: "center",
    color: "#fff",
  },
  draggableContainer: {
    position: "absolute",
    top: Screen.height / 2 - CIRCLE_RADIUS,
    left: Screen.width / 2 - CIRCLE_RADIUS,
  },
  circle: {
    backgroundColor: "#1abc9c",
    width: CIRCLE_RADIUS * 2,
    height: CIRCLE_RADIUS * 2,
    borderRadius: CIRCLE_RADIUS,
  },
});

Check out this similar animation of badge Above ScrollView.查看 ScrollView 上方徽章的类似 animation。

You need to place the Image inside an Animated View.您需要将图像放置在动画视图中。

Example code:示例代码:

import React, {Component} from 'react';
import {
  StyleSheet,
  View,
  PanResponder,
  Animated,
  Dimensions,
  ScrollView,
  Image,
} from 'react-native';

const {height, width} = Dimensions.get('screen');

export default class SampleApp extends Component {
  constructor() {
    super();
    this._animatedValue = new Animated.ValueXY({x: 20, y: 20});
    this._value = {x: 20, y: 20};
    this._animatedValue.addListener((value) => (this._value = value));
    this._panResponder = PanResponder.create({
      onMoveShouldSetResponderCapture: () => true,
      onMoveShouldSetPanResponderCapture: () => true,
      onPanResponderGrant: (e, gestureState) => {
        this._animatedValue.setOffset({x: this._value.x, y: this._value.y});
        this._animatedValue.setValue({x: 0, y: 0});
      },
      onPanResponderMove: Animated.event([
        null,
        {dx: this._animatedValue.x, dy: this._animatedValue.y},
      ]),
      onPanResponderRelease: (e, gesture) => {
        this._animatedValue.flattenOffset();
        if (this.whichField(gesture) == 1) {
          Animated.spring(this._animatedValue, {
            toValue: {x: 20, y: 20},
          }).start();
        } else if (this.whichField(gesture) == 2) {
          Animated.spring(this._animatedValue, {
            toValue: {x: width - 120, y: 20},
          }).start();
        } else if (this.whichField(gesture) == 3) {
          Animated.spring(this._animatedValue, {
            toValue: {x: 20, y: height - 150},
          }).start();
        } else {
          Animated.spring(this._animatedValue, {
            toValue: {x: width - 120, y: height - 150},
          }).start();
        }
      },
    });
  }

  whichField(gesture) {
    var sm = {height, width};
    let field;
    {
      gesture.moveY < sm.height / 2 && gesture.moveX < sm.width / 2
        ? (field = 1)
        : gesture.moveY < sm.height / 2 && gesture.moveX > sm.width / 2
        ? (field = 2)
        : gesture.moveY > sm.height / 2 && gesture.moveX < sm.width / 2
        ? (field = 3)
        : (field = 4);
    }
    return field;
  }

  render() {
    return (
      <View style={styles.container}>
        <ScrollView>
          {['', '', '', '', '', ''].map(() => (
            <View style={styles.scrollItem} />
          ))}
        </ScrollView>
        <Animated.View
          style={[
            styles.box,
            {
              transform: [
                {translateX: this._animatedValue.x},
                {translateY: this._animatedValue.y},
              ],
            },
          ]}
          {...this._panResponder.panHandlers}>
          <Image
            source={{
              uri:
                'https://pluspng.com/img-png/user-png-icon-male-user-icon-512.png',
            }}
            style={StyleSheet.absoluteFill}
          />
        </Animated.View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  box: {
    width: 100,
    height: 100,
    borderRadius: 50,
    backgroundColor: '#fff',
    position: 'absolute',
  },
  scrollItem: {
    height: 300,
    width: '100%',
    backgroundColor: 'grey',
    marginBottom: 10,
  },
});

Check in Expo签入 Expo

I hope it will help you.我希望它会帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当Animated.View将Animated.ScrollView作为子项时,PanResponder在Android上无法正常工作 - PanResponder not working properly on Android when Animated.View has an Animated.ScrollView as a child PanResponder在第二次拖动时将Animated.View捕捉回原始位置 - PanResponder snaps Animated.View back to original position on second drag 为什么 Animated.View 中的 ScrollView 不起作用? - why ScrollView inside Animated.View not working? Animated.View 仅适用于展开,不适用于折叠 - Animated.View only works on expanding, not on collapsing 如何使 React Native Animated.View 可点击? - How to make React Native Animated.View clickable? 为 React-Native 应用开玩笑测试 Animated.View - Jest test Animated.View for React-Native app React Native - Animated.View 与常规 View 组件之间的性能差异 - React Native - Performance difference between Animated.View vs regular View component 在 Animated.View 中反应 Native ScrollView 以制作类似 Bumble 的滑动系统 - React Native ScrollView inside an Animated.View to make Bumble-like swipe system 即使 animation 变量的值正在更新,Animated.View 样式也没有改变 - Animated.View style not changing even thought the value of animation variable is getting updated 检测何时触摸另一个视图 - 使用PanResponder以本机方式拖动 - detect when another view is touched - dragging with PanResponder in react native
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM