我正在用反应式刷新的标签导航器进行自己的实现。它可以正常工作,但是当我的一个选项卡中有一个滚动显示时,它似乎会破裂。左右滑动更改选项卡的效果很好,并且在ScrollView中向下滚动。当我单击以拖动滚动视图,然后侧向移动而无需释放以滑动时,它会破裂。然后"选项卡系统"仅重置为第一个选项卡。
我做了一个黑客,当滚动滚动时,我会从选项卡中禁用刷子。这有效,但感觉就像是一个不好的解决方案,因为标签内容必须意识到它在选项卡中。
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>
);
}
}
尝试使用一个函数进行onMoveshouldSetSeponder,因此仅在GestureState.dx远大于gesturestate.dy时才能水平刷。
onMoveShouldSetResponder: (evt, gestureState) => {
return Math.abs(gestureState.dx) > Math.abs(gestureState.dy * 3);
},
您还可以在Onpanrespondermove中具有功能,跟踪滑动手势的方向,然后在OnpanresponderRelease中重置,因此当垂直滑动变成类似的水平滑动时,您就不会遇到问题:
: >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;
}
我在媒体上如何构建react react tab视图,在网上找到了一篇很棒的文章。我建议您查看博客文章,因为这对我真的很有帮助。
更新:在此处查看文档,如果您希望父母组件防止子组件成为手势响应者,反之亦然。
,或者您可以尝试使用我的uter unation-scroll-croll-locky,然后将其与..!
搭配。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>
);
}
}
现在,您将其应用到的滚动视图只会响应您想要的方向,而他们两个不会再次感到困惑。
在您的视图控制器中使用您的代码块(scrollview,pan手势(,
写下此功能:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
希望它有帮助。:(