我创建了具有三个 View 的ScrollView
。我想将拖动的 View 绑定(bind)到 ScrollView
内部,其余未拖放的 View 应保留在 ScrollView
外部。怎么可能。
查看 GIF:我想在 ScrollView 中添加draggableView。
代码:
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
PanResponder,
Animated,
Easing,
Dimensions,
Platform,
TouchableOpacity,
ScrollView,
} from 'react-native';
import Carousel from 'react-native-snap-carousel';
let CIRCLE_RADIUS = 36;
let Window = Dimensions.get('window');
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
export default class App extends Component<{}> {
constructor(props){
super(props);
this.dataDrag = [1,2,3,4],
this.pan = this.dataDrag.map( () => new Animated.ValueXY() );
this.state = {
showDraggable : true,
dropZoneValues : null,
entries : ['Apple1' , 'Apple2', 'Apple3']
};
}
getPanResponder(index) {
return PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove : Animated.event([null,{
dx : this.pan[index].x,
dy : this.pan[index].y
}]),
onPanResponderRelease : (e, gesture) => {
if(this.isDropZone(gesture)){
this.setState({
showDraggable : false
});
}else{
Animated.spring(
this.pan[index],
{toValue:{x:0,y:0}}
).start();
}
}
});
}
isDropZone(gesture){
var dz = this.state.dropZoneValues;
return gesture.moveY > dz.y && gesture.moveY < dz.y + dz.height;
}
setDropZoneValues(event){
console.log('event.nativeEvent.layout', event.nativeEvent.layout);
this.setState({
dropZoneValues : event.nativeEvent.layout
});
}
_renderItem ({item, index}) {
return (
<View style={{width: Dimensions.get('window').width - 100 , height : 150 , backgroundColor : 'red' , marginLeft : 50 , marginRight : 50}}>
<Text style={{color : 'black' , marginTop : 20}}>{item}</Text>
</View>
);
}
render(){
return (
<View style={styles.mainContainer}>
<ScrollView>
<View onLayout={this.setDropZoneValues.bind(this)}
style={[styles.dropZone , {marginTop : 10}]}>
</View>
<View onLayout={this.setDropZoneValues.bind(this)}
style={[styles.dropZone , {marginTop : 10}]}>
</View>
<View onLayout={this.setDropZoneValues.bind(this)}
style={[styles.dropZone , {marginTop : 10}]}>
</View>
</ScrollView>
{this.dataDrag.map((d, index) => (
<Animated.View
key={index}
{...this.getPanResponder(index).panHandlers}
style={[styles.draggableContainer, this.pan[index].getLayout(), styles.circle]}>
<Text style={styles.text}>Drag {index}</Text>
</Animated.View>
))}
</View>
);
}
}
let styles = StyleSheet.create({
mainContainer: {
flex : 1
},
dropZone : {
height : 100,
backgroundColor:'#2c3e50'
},
text : {
marginTop : 25,
marginLeft : 5,
marginRight : 5,
textAlign : 'center',
color : '#fff'
},
draggableContainer: {
position : 'absolute',
marginTop : Window.height/2 - CIRCLE_RADIUS,
marginLeft : Window.width/2 - CIRCLE_RADIUS,
},
circle : {
backgroundColor : '#1abc9c',
width : CIRCLE_RADIUS*2,
height : CIRCLE_RADIUS*2,
borderRadius : CIRCLE_RADIUS
},
});
最佳答案
其基本思想是创建两个数组,通过从一个结构中删除并复制到另一个结构来模拟移动效果。
逐步:
创建两个数组
this.state = { dataDrag: [...this.dataDrag], dataDragged: [], };
OnPanResponderRelease
,移至新数组。onPanResponderRelease : (e, gesture) => { if(this.isDropZone(gesture)){ let idx = this.state.dataDrag.indexOf(index+1); this.setState({ showDraggable : false, dataDrag: [ ...this.state.dataDrag.slice(0, idx), ...this.state.dataDrag.slice(idx+1, this.state.dataDrag.length-1) ], dataDragged: [...this.state.dataDragged, this.state.dataDrag[idx]], }); }
创建两组
Animated.View
,一组在ScollView
内部,一组在其外部。
最终代码:
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
PanResponder,
Animated,
Easing,
Dimensions,
Platform,
TouchableOpacity,
ScrollView,
} from 'react-native';
let CIRCLE_RADIUS = 36;
let Window = Dimensions.get('window');
export class App extends Component<{}> {
constructor(props){
super(props);
this.dataDrag = [1,2,3,4],
this.pan = this.dataDrag.map( () => new Animated.ValueXY() );
this.state = {
showDraggable : true,
dropZoneValues : null,
entries : ['Apple1' , 'Apple2', 'Apple3'],
dataDrag: [...this.dataDrag],
dataDragged: [],
};
}
getPanResponder(index) {
return PanResponder.create({
onStartShouldSetPanResponder: () => {
return true;
},
onPanResponderMove : Animated.event([null,{
dx : this.pan[index].x,
dy : this.pan[index].y
}]),
onPanResponderRelease : (e, gesture) => {
if(this.isDropZone(gesture)){
let idx = this.state.dataDrag.indexOf(index+1);
this.setState({
showDraggable : false,
dataDrag: [ ...this.state.dataDrag.slice(0, idx), ...this.state.dataDrag.slice(idx+1, this.state.dataDrag.length-1) ],
dataDragged: [...this.state.dataDragged, this.state.dataDrag[idx]],
});
}else{
Animated.spring(
this.pan[index],
{toValue:{x:0,y:0}}
).start();
}
}
});
}
isDropZone(gesture){
var dz = this.state.dropZoneValues;
return gesture.moveY > dz.y && gesture.moveY < dz.y + dz.height;
}
setDropZoneValues(event){
this.setState({
dropZoneValues : event.nativeEvent.layout
});
}
_renderItem ({item, index}) {
return (
<View style={{width: Dimensions.get('window').width - 100 , height : 150 , backgroundColor : 'red' , marginLeft : 50 , marginRight : 50}}>
<Text style={{color : 'black' , marginTop : 20}}>{item}</Text>
</View>
);
}
render(){
return (
<View style={styles.mainContainer}>
<ScrollView>
<View onLayout={this.setDropZoneValues.bind(this)}
style={[styles.dropZone , {marginTop : 10}]}>
</View>
<View onLayout={this.setDropZoneValues.bind(this)}
style={[styles.dropZone , {marginTop : 10}]}>
</View>
<View onLayout={this.setDropZoneValues.bind(this)}
style={[styles.dropZone , {marginTop : 10}]}>
</View>
{this.state.dataDragged.map((d, index) => (
<Animated.View
key={d-1}
style={[styles.draggableContainer, this.pan[d-1].getLayout(), styles.circle]}>
<Text style={styles.text}>Drag {d-1}</Text>
</Animated.View>
))}
</ScrollView>
{this.state.dataDrag.map((d, index) => (
<Animated.View
key={d-1}
{...this.getPanResponder(d-1).panHandlers}
style={[styles.draggableContainer, this.pan[d-1].getLayout(), styles.circle]}>
<Text style={styles.text}>Drag {d-1}</Text>
</Animated.View>
))}
</View>
);
}
}
let styles = StyleSheet.create({
mainContainer: {
flex : 1
},
dropZone : {
height : 100,
backgroundColor:'#2c3e50'
},
text : {
marginTop : 25,
marginLeft : 5,
marginRight : 5,
textAlign : 'center',
color : '#fff'
},
draggableContainer: {
position : 'absolute',
marginTop : Window.height/2 - CIRCLE_RADIUS,
marginLeft : Window.width/2 - CIRCLE_RADIUS,
},
circle : {
backgroundColor : '#1abc9c',
width : CIRCLE_RADIUS*2,
height : CIRCLE_RADIUS*2,
borderRadius : CIRCLE_RADIUS
},
});
结果:
关于reactjs - 如何将拖动 View 绑定(bind)到ScrollView项目中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47566739/