当要设置动画的项目位于可滚动视图前面时,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,
},
});
希望对你有所帮助
大家好 :) 应该是贴在最近角落的导航头像的功能。在编码时,我使用了一个简单的圆圈作为占位符。问题是以下代码在导入到另一个屏幕时工作得很好,但是当我用图像 <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,
},
});
希望对你有所帮助