[英]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,
},
});
I hope it will help you.我希望它会帮助你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.