Javascript PanResponder中的滚动视图
我正在通过在React Native中滑动来实现我自己的选项卡导航器。它工作得很好,但当我的一个标签中有一个滚动视图时,它似乎坏了。向左和向右滑动以更改选项卡工作正常,并且在scrollview中向下和向上滚动。当我单击拖动scrollView,然后侧移而不释放以进行滑动时,它会断开。然后选项卡系统将重置为第一个选项卡 我做了一个黑客,当滚动视图时,我禁用从选项卡内部滑动。这是可行的,但感觉像是一个糟糕的解决方案,因为选项卡内容必须知道它在选项卡中Javascript PanResponder中的滚动视图,javascript,ios,react-native,tabs,uiscrollview,Javascript,Ios,React Native,Tabs,Uiscrollview,我正在通过在React Native中滑动来实现我自己的选项卡导航器。它工作得很好,但当我的一个标签中有一个滚动视图时,它似乎坏了。向左和向右滑动以更改选项卡工作正常,并且在scrollview中向下和向上滚动。当我单击拖动scrollView,然后侧移而不释放以进行滑动时,它会断开。然后选项卡系统将重置为第一个选项卡 我做了一个黑客,当滚动视图时,我禁用从选项卡内部滑动。这是可行的,但感觉像是一个糟糕的解决方案,因为选项卡内容必须知道它在选项卡中 import React, { Compone
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { View, Animated, Dimensions, PanResponder } from 'react-native';
import Immutable from 'immutable';
import Tab1 from './Tab1';
import Tab2 from './Tab2';
import ScrollViewTab from './ScrollViewTab';
@connect(
state => ({
tabs: state.tabs
})
)
export default class Tabs extends Component {
static propTypes = {
tabs: PropTypes.instanceOf(Immutable.Map).isRequired,
dispatch: PropTypes.func.isRequired
};
constructor(props) {
super(props);
this.justLoaded = true;
this.state = {
left: new Animated.Value(0),
tabs: [{ // Tabs must be in order, despite index.
name: 'tab1',
component: <Tab1 setTab={this.setTab} />,
index: 0
}, {
name: 'tab2',
component: <Tab2 setTab={this.setTab} />,
index: 1
}, {
name: 'scrollViewTab',
component: <ScrollViewTab setTab={this.setTab} />,
index: 2
}]
};
this.getIndex = this.getIndex.bind(this);
}
componentWillMount() {
this.panResponder = PanResponder.create({
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
if (Math.abs(gestureState.dx) > 10) {
return true;
}
return false;
},
onPanResponderGrant: () => {
this.state.left.setOffset(this.state.left._value);
this.state.left.setValue(0);
},
onPanResponderMove: (e, gestureState) => {
if (this.isSwipingOverLeftBorder(gestureState) ||
this.isSwipingOverRightBorder(gestureState)) return;
Animated.event([null, {
dx: this.state.left
}])(e, gestureState);
},
onPanResponderRelease: (e, gestureState) => {
this.state.left.flattenOffset();
if (this.isSwipingOverLeftBorder(gestureState) ||
this.isSwipingOverRightBorder(gestureState)) {
return;
}
Animated.timing(
this.state.left,
{ toValue: this.calcX(gestureState) }
).start();
}
});
}
componentDidMount() {
this.justLoaded = false;
}
getStyle() {
const oldLeft = this.state.left;
let left = 0;
const screenWidth = Dimensions.get('window').width;
// Set tab carouselle coordinate to match the selected tab.
this.state.tabs.forEach((tab) => {
if (tab.name === this.props.tabs.get('tab')) {
left = -tab.index * screenWidth;
}
});
if (this.justLoaded) {
Animated.timing(
this.state.left,
{ toValue: left,
duration: 0
}
).start();
return { transform: [{ translateX: oldLeft }], flexDirection: 'row', height: '100%' };
}
Animated.timing(
this.state.left,
{ toValue: left
}
).start();
return { transform: [{ translateX: oldLeft }], flexDirection: 'row', height: '100%' };
}
getIndex(tabN) {
let index = 0;
this.state.tabs.forEach((tab) => {
if (tab.name === tabN) {
index = tab.index;
}
return tab;
});
return index;
}
setTab(tab, props) {
this.navProps = props;
this.props.dispatch({ type: 'SET_TAB', tab });
}
isSwipingOverLeftBorder(gestureState) {
return (this.props.tabs.get('tab') === this.state.tabs[0].name &&
gestureState.dx > 0);
}
isSwipingOverRightBorder(gestureState) {
return (this.props.tabs.get('tab') === this.state.tabs[this.state.tabs.length - 1].name &&
gestureState.dx < 0);
}
calcX(gestureState) {
const screenWidth = Dimensions.get('window').width;
const activeTab = this.getIndex(this.props.tabs.get('tab'));
let coord = 0;
if (gestureState.dx > screenWidth * 0.2) {
coord = (activeTab * screenWidth) - screenWidth;
} else if (gestureState.dx < -(screenWidth * 0.2)) {
coord = (activeTab * screenWidth) + screenWidth;
} else {
coord = activeTab * screenWidth;
}
this.updateTab(-coord, screenWidth);
return -coord;
}
updateTab(coord, screenWidth) {
// Update current tab according to location and screenwidth
this.state.tabs.forEach((tab) => {
if (coord === -tab.index * screenWidth) {
this.props.dispatch({ type: 'SET_TAB', tab: tab.name });
}
});
}
render() {
return (
<View
style={{ flex: 1 }}
>
<Animated.View
style={this.getStyle()}
{...this.panResponder.panHandlers}
>
{this.state.tabs.map(tab => tab.component)}
</Animated.View>
</View>
);
}
}
import React,{Component,PropTypes}来自'React';
从'react redux'导入{connect};
从“react native”导入{视图、动画、维度、PanResponder};
从“不可变”导入不可变;
从“/Tab1”导入Tab1;
从“/Tab2”导入Tab2;
从“/ScrollViewTab”导入ScrollViewTab;
@连接(
状态=>({
选项卡:state.tabs
})
)
导出默认类选项卡扩展组件{
静态类型={
选项卡:PropTypes.instanceOf(Immutable.Map).isRequired,
调度:需要PropTypes.func.isRequired
};
建造师(道具){
超级(道具);
this.justLoaded=true;
此.state={
左:新动画。值(0),
制表符:[{//制表符必须有序,不管索引如何。
名称:'tab1',
组成部分:,
索引:0
}, {
名称:'tab2',
组成部分:,
索引:1
}, {
名称:'scrollViewTab',
组成部分:,
索引:2
}]
};
this.getIndex=this.getIndex.bind(this);
}
组件willmount(){
this.panResponder=panResponder.create({
onMoveShouldSetResponderCapture:()=>true,
onMoveShouldSetPanResponderCapture:(evt,手势状态)=>{
if(Math.abs(gestureState.dx)>10){
返回true;
}
返回false;
},
onPanResponderGrant:()=>{
this.state.left.setOffset(this.state.left.\u值);
此.state.left.setValue(0);
},
onPanResponderMove:(e,手势状态)=>{
if(this.isSwipingOverLeftBorder(gestureState)||
此.isSwipingOverRightBorder(gestureState))返回;
已设置动画的.event([null{
dx:这个。州。左
}])(e)手势状态;
},
onPanResponderRelease:(e,手势状态)=>{
this.state.left.flattOffset();
if(this.isSwipingOverLeftBorder(gestureState)||
此.IsWipingOverRightBorder(gestureState)){
返回;
}
时间(
这个州,左,
{toValue:this.calcX(gestureState)}
).start();
}
});
}
componentDidMount(){
this.justLoaded=false;
}
getStyle(){
const oldlift=this.state.left;
设左=0;
const screenWidth=Dimensions.get('window').width;
//将制表符转盘坐标设置为与所选制表符匹配。
this.state.tabs.forEach((tab)=>{
if(tab.name==this.props.tabs.get('tab')){
左=-tab.index*屏幕宽度;
}
});
如果(此.justLoaded){
时间(
这个州,左,
{toValue:left,
持续时间:0
}
).start();
返回{transform:[{translateX:oldLeft}],flexDirection:'row',height:'100%};
}
时间(
这个州,左,
{toValue:左
}
).start();
返回{transform:[{translateX:oldLeft}],flexDirection:'row',height:'100%};
}
getIndex(tabN){
设指数=0;
this.state.tabs.forEach((tab)=>{
如果(tab.name==tabN){
索引=tab.index;
}
返回选项卡;
});
收益指数;
}
设置选项卡(选项卡,道具){
this.navProps=props;
this.props.dispatch({type:'SET_TAB',TAB});
}
isSwipingOverLeftBorder(gestureState){
return(this.props.tabs.get('tab')==this.state.tabs[0]。name&&
gestureState.dx>0);
}
isSwipingOverRightBorder(手势状态){
return(this.props.tabs.get('tab')==this.state.tabs[this.state.tabs.length-1].name&&
gestureState.dx<0);
}
calcX(手势状态){
const screenWidth=Dimensions.get('window').width;
const activeTab=this.getIndex(this.props.tabs.get('tab');
设coord=0;
如果(gestureState.dx>屏幕宽度*0.2){
坐标=(activeTab*屏幕宽度)-屏幕宽度;
}else if(gestureState.dx<-(屏幕宽度*0.2)){
坐标=(activeTab*屏幕宽度)+屏幕宽度;
}否则{
coord=activeTab*屏幕宽度;
}
this.updateTab(-coord,screenWidth);
回归协调;
}
更新选项卡(坐标,屏幕宽度){
//根据位置和屏幕宽度更新当前选项卡
this.state.tabs.forEach((tab)=>{
如果(坐标===-tab.index*屏幕宽度){
this.props.dispatch({type:'SET_TAB',TAB:TAB.name});
}
});
}
render(){
返回(
{this.state.tabs.map(tab=>tab.component)}
);
}
}
在使用代码块的视图控制器中(滚动视图、平移手势)
编写此函数:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
希望有帮助。:)尝试使用onMoveS函数
onMoveShouldSetResponder: (evt, gestureState) => {
return Math.abs(gestureState.dx) > Math.abs(gestureState.dy * 3);
},
checkSwipeDirection(gestureState) {
if(
(Math.abs(gestureState.dx) > Math.abs(gestureState.dy * 3) ) &&
(Math.abs(gestureState.vx) > Math.abs(gestureState.vy * 3) )
) {
this._swipeDirection = "horizontal";
} else {
this._swipeDirection = "vertical";
}
}
canMove() {
if(this._swipeDirection === "horizontal") {
return true;
} else {
return false;
}
}
onMoveShouldSetPanResponder: this.canMove,
onPanResponderMove: (evt, gestureState) => {
if(!this._swipeDirection) this.checkSwipeDirection(gestureState);
// Your other code here
},
onPanResponderRelease: (evt, gestureState) => {
this._swipeDirection = null;
}
import RNLocky from "react-native-scroll-locky";
class WhateverClass extends Component {
constructor(props) {
super(props);
this.directionLockPanHandler = new RNLocky(
RNLocky.Direction.HORIZONTAL, // or RNLocky.Direction.VERTICAL
);
}
render() {
return (
<ScrollView
{...this.directionLockPanHandler.getPanHandlers()}
>
<ScrollView>
...
</ScrollView>
</ScrollView>
);
}
}