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

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

大家好 :) 应该是贴在最近角落的导航头像的功能。在编码时,我使用了一个简单的圆圈作为占位符。问题是以下代码在导入到另一个屏幕时工作得很好,但是当我用图像 <Image source={require("../assets/dude.png")} resizeMode="contain" style={{width: 180, height: 240,}}/> 替换 <View style={styles.circle} /> 时它不再工作了吗?就像我能看到图像一样,但是动画工作时非常有问题,而且它随处可见,没有像它应该做的那样?

我也尝试过使用 Animated.Image 而不是视图并为其提供所有参数,但仍然没有变化。奇怪的是,如果我将 运行 这段代码作为屏幕本身,图像工作得很好,但是当我导入它时,只有圆形视图有效,而不是图像?

编辑:刚发现问题:如果 Animated.Image 位于可滚动视图的前面,即使它不是该视图的一部分,它也会出错。如果我用其他任何东西(比如盒子)替换图像,它工作正常,只有图像以这种方式出现错误 :) 这引出了我的下一个问题:我该如何解决?

所以这是我的代码:

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,
  },
});

查看 ScrollView 上方徽章的类似动画。

您需要将图像放在动画视图中。

示例代码:

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

希望对你有所帮助