我的示例代码是在PanResponder的onPanResponderRelease释放之后自动移动一个距离(看起来像是物体移动惯性)。
当我拖动内容并松开手指(或在模拟器中释放拖动)时,内容正常工作(它自动移动了一段距离)。 但是当我快速触摸(或在模拟器中单击一次)时,内容会移动一段距离并返回到其他位置。这是有问题的,因为不应快速触摸内容。
出什么问题了? 这是我的代码(它可以直接粘贴并在app.js中运行。)
import React from 'react';
import { View, StyleSheet, PanResponder, Animated, Text, Button, } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this._layout = { x: 0, y: 0, width: 0, height: 0, };
this._value = { x: 100, y: 100, };
}
componentWillMount() {
this._animatedValue = new Animated.ValueXY({ x: 100, y: 100 });
this._animatedValue.addListener((value) => {
this._value = value;
});
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => ((gestureState.dx != 0) && (gestureState.dy != 0)),
onPanResponderGrant: (e, gestureState) => {
this._animatedValue.setOffset({ x: this._value.x, y: this._value.y });
},
onPanResponderMove: Animated.event([
null,
{ dx: this._animatedValue.x, dy: this._animatedValue.y },
]),
onPanResponderRelease: () => {
this._animatedValue.flattenOffset();
Animated.timing(
this._animatedValue,
{
toValue: { x: this._value.x, y: this._value.y + 100, },
duration: 600,
}
).start(() => {
// animation finished
});
}
});
}
render() {
return (
<View style={styles.container}>
<Animated.View
style={[
styles.box,
{
left: this._animatedValue.x,
top: this._animatedValue.y,
},
]}
{...this._panResponder.panHandlers}
>
<Text>{'This is a test'}</Text>
<Button
title={'Click Me'}
onPress={() => console.log('Yes, I clicked.')}
/>
</Animated.View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
},
box: {
width: 200,
height: 200,
borderWidth: 1,
},
});
非常感谢!
答案 0 :(得分:1)
我不确定这有多重要,但是您没有按照建议的方式添加事件监听器:https://facebook.github.io/react-native/docs/animated#event
尝试像这样添加它:
componentWillMount() {
this._animatedValue = new Animated.ValueXY({ x: 100, y: 100 });
// REMOVE THIS
//this._animatedValue.addListener((value) => {
// this._value = value;
//});
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => ((gestureState.dx != 0) && (gestureState.dy != 0)),
onPanResponderGrant: (e, gestureState) => {
this._animatedValue.setOffset({ x: this._value.x, y: this._value.y });
},
onPanResponderMove: Animated.event([
null,
{ dx: this._animatedValue.x, dy: this._animatedValue.y },
],
{
SEE HERE--->>> listener: this.onMove
}
),
onPanResponderRelease: () => {
this._animatedValue.flattenOffset();
Animated.timing(
this._animatedValue,
{
toValue: { x: this._value.x, y: this._value.y + 100, },
duration: 600,
}
).start(() => {
// animation finished
});
}
});
}
AND SEE HERE --->>>
onMove() {
var { x, y } = this.animatedValue;
this._value.x = x;
this._value.y = y;
}
也请尝试制作Animated.View position:absolute
现在,看起来代码正在执行此操作:
将“动画偏移”设置为等于“值偏移”(onPanResponderGrant)
将“动画偏移”设置为等于“ dx”,“ dy”(onPanResponderMove)
将“值”设置为等于“动画值”(事件监听器)
将“动画值”设置为等于“值”(onPanResponderRelease)
在步骤1和步骤2之间,您两次设置了偏移量而没有变平(同样,不确定有多重要)。
在第三步和第四步之间,您将“值偏移量”设置为“动画值偏移量”,然后将“动画值偏移量”设置为再次等于“值偏移量”-似乎是多余的
答案 1 :(得分:0)
我写了一个新版本,并得到了结果。
import React, { Component } from 'react';
import {
StyleSheet, View, Text, Animated, PanResponder,
} from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this._value = { x: 0, y: 0 };
this.pan = new Animated.ValueXY({ x: 0, y: 0 });
}
componentWillMount() {
this.pan.addListener((value) => {
this._value = value;
});
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => ((gestureState.dx != 0) && (gestureState.dy != 0)),
onPanResponderGrant: (e, gestureState) => {
this.pan.setOffset({ x: this._value.x, y: this._value.y });
this.pan.setValue({ x: 0, y: 0 });
},
onPanResponderMove: Animated.event([null, {
dx: this.pan.x,
dy: this.pan.y
}]),
onPanResponderRelease: (e, gesture) => {
this.pan.flattenOffset();
const { x, y } = this._value;
Animated.timing(
this.pan,
{
toValue: { x, y: y + 50 },
duration: 600,
},
).start(() => {
// animation finished
});
}
});
}
componentWillUnmount() {
this.pan.removeAllListener();
}
render() {
return (
<View style={{ flex: 1 }}>
<View style={styles.draggableContainer}>
<Animated.View
{...this.panResponder.panHandlers}
style={[
this.pan.getLayout(),
styles.square,
]}>
<Text>Drag me!</Text>
</Animated.View>
</View>
</View>
);
}
}
let styles = StyleSheet.create({
draggableContainer: {
position: 'absolute',
top: 165,
left: 76.1,
},
square: {
backgroundColor: 'red',
width: 72,
height: 72,
borderWidth: 1,
}
});
以前的版本存在一些问题,因为我不知道本机动画。
关于代码有几点:
1)动画视图应由position:绝对视图包裹。
2)动画值/ valueXY是相对位置。
3)addListener正常工作。
4)valueXY是具有两个值对象的组合对象。 但是addListener参数是具有x / y的对象,例如:{x:0,y:0}
(因此,valueXY和侦听器参数无法直接分配)
5)动画会添加值的偏移量。
flattenOffset之后,偏移量将添加到值中。