[英]How do I make a secondary <View> enter a main view with the PanResponder?
When the View mounts, I would like the secondary view to be off the screen to the right of the main view.当视图安装时,我希望辅助视图位于主视图右侧的屏幕之外。
When the user pan swipes left , the secondary view should follow the pan and eventually cover the main view.当用户平移向左滑动时,辅助视图应该跟随平移并最终覆盖主视图。 (like Instagram camera) (如 Instagram 相机)
I have a basic structure set up, but I'm not sure how to finalize the <Animated.View>
part.我已经设置了一个基本结构,但我不确定如何完成<Animated.View>
部分。 For example, do I put the pan handler on the main view or on the secondary view?例如,我是将平移处理程序放在主视图上还是放在次要视图上? I don't want the secondary view to cover any interactions on the main view.我不希望辅助视图覆盖主视图上的任何交互。
import React from 'react';
import { PanResponder, Animated, Dimensions, StyleSheet, Text, View } from 'react-native';
const winWidth = Dimensions.get('window').width
const winHeight = Dimensions.get('window').height
class Main extends React.Component {
constructor(props){
super(props);
}
translateX = new Animated.Value(0);
panResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: (e, gs) => {
return gs.dx < 0 //allow left only
},
onPanResponderMove: (e, gs) => {
if(gs.dx < 0) {
Animated.event([null, {dx: this.translateX}])(e, gs)
}
},
onPanResponderRelease: (e, {vx, dx}) => {
//Secondary View should now cover the main View
},
onPanResponderTerminationRequest: (e, gs) => {
return false
},
onPanResponderTerminate: (e, {vx, dx} ) => {
},
})
render(){
return(
<View style={{styles.main}}>
<View style={{styles.secondary}}></View>
<View><Text>Other components will be displayed</Text></View>
</View>
)
}
}
const styles = StyleSheet.create({
main:{
flex:1,
flexDirection:'column',
backgroundColor: '#ffffff'
},
secondary:{
width: winWidth,
height: winHeight,
backgroundColor: 'red',
position: 'absolute',
top:0,
left:winWidth, //start off screen
},
})
I am not sure if this is what you are after but the way I did it was nesting two View inside the Animated.View Component which cover the full screen.我不确定这是否是您所追求的,但我这样做的方式是在 Animated.View 组件中嵌套两个视图,覆盖全屏。
<Animated.View style={[this.position.getLayout(), {display: 'flex', flex: 1, flexDirection: 'row'}]} {...this.panResponder.panHandlers}>
<View style={{width: '100%', height: '100%', backgroundColor: 'yellow'}}>
<Text>
This is the Main view
</Text>
</View>
<View style={{ height: '100%', width: '100%', backgroundColor: 'red'}}>
<Text>
This is the invisible View
</Text>
</View>
</Animated.View>
The styling in the Views is to make each cover the full width视图中的样式是使每个都覆盖整个宽度
inside the Animated.View I used the array notation to apply two styles在 Animated.View 中,我使用数组表示法来应用两种样式
this.position.getLayout() is the one that gives the coordinates/position of where the Animated.View component should be this.position.getLayout()是给出 Animated.View 组件所在位置的坐标/位置
The other styling object is so we can render the child views next to each other using flexbox particularly setting另一个样式对象是这样我们可以使用 flexbox 特别设置来渲染彼此相邻的子视图
Also attach the panHandlers to the Animated.View还将 panHandlers 附加到 Animated.View
constructor(props){ super(props) position = new Animated.ValueXY() const panResponder = PanResponder.create({ onStartShouldSetPanResponder: ()=> true, onPanResponderMove: (evt, gesture)=>{ //Need to set theshhold and state.isOpen to determine direction here position.setValue({x: gesture.dx, y: 0}) }, onPanResponderGrant: ()=>{ this.position.setOffset({x: this.position.x._value, y: 0}) this.position.setValue({x: 0, y: 0}) }, onPanResponderRelease: ()=>{ this.openOrClose() } }) this.state = {isOpen: false} this.panResponder = panResponder this.position = position }
I used state to monitor where the View Should move to this.state = {isOpen: false} depending on which view was visible.我使用状态来监视视图应该移动到this.state = {isOpen: false} 的位置,具体取决于哪个视图可见。
The functions to move are mainly position.setValue({x: gesture.dx, y: 0}) which tracks the movement while the touch/pan is still active and this.openOrClose() which is called when the touch/pan is released.移动的函数主要是position.setValue({x:gesture.dx, y: 0}) ,它在触摸/平移仍处于活动状态时跟踪移动,以及this.openOrClose()在释放触摸/平移时调用.
The openOrClose function determines how to handle the movement and the main logic should be here. openOrClose 函数决定了如何处理移动,主要逻辑应该在这里。 I just did a simple case and did not include any threshHold in this example.我只是做了一个简单的案例,在这个例子中没有包含任何 threshHold。
To understand panHandlers I suggest you read this article as it explains the reasons for onPanResponderGrant best.要了解 panHandlers,我建议您阅读这篇文章,因为它最好地解释了onPanResponderGrant的原因。
Below is the code for the working Component下面是工作组件的代码
import React, {Component} from 'react' import {View, Text, Animated, PanResponder, Dimensions} from 'react-native' const ScreenWidth = Dimensions.get('window').width //Logic to flattenOffset required export class Swipable extends Component{ constructor(props){ super(props) position = new Animated.ValueXY() const panResponder = PanResponder.create({ onStartShouldSetPanResponder: ()=> true, onPanResponderMove: (evt, gesture)=>{ //Need to set theshhold and state.isOpen to determine direction here position.setValue({x: gesture.dx, y: 0}) }, onPanResponderGrant: ()=>{ this.position.setOffset({x: this.position.x._value, y: 0}) this.position.setValue({x: 0, y: 0}) }, onPanResponderRelease: ()=>{ this.openOrClose() } }) this.state = {isOpen: false} this.panResponder = panResponder this.position = position } openOrClose = ()=>{ this.position.flattenOffset() //determine where to move depending onState direction = this.state.isOpen ? 0 : -ScreenWidth Animated.spring(this.position, { toValue: {x: direction, y: 0} }).start(()=>{ //Callback when animation is complete to show if open or closed this.setState((prevState)=>{ return {isOpen: !prevState.isOpen} }) }) } render(){ return( <Animated.View style={[this.position.getLayout(), {display: 'flex', flex: 1, flexDirection: 'row'}]} {...this.panResponder.panHandlers}> <View style={{width: '100%', height: '100%', backgroundColor: 'yellow'}}> <Text> This is the Main view </Text> </View> <View style={{ height: '100%', width: '100%', backgroundColor: 'red'}}> <Text> This is the invisible View </Text> </View> </Animated.View> ) } }
I ran the above code on an Android emulator, I am sure it will work on ios.我在 Android 模拟器上运行了上面的代码,我相信它可以在 ios 上运行。 If there is anything I need to clarify or improve please do tell me如果有什么我需要澄清或改进的,请告诉我
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.