Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for android #797

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions SceneComponent.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const React = require('react');
const ReactNative = require('react-native');
const {Component, } = React;
const {View, StyleSheet, } = ReactNative;
const {Component } = React;
const {View, StyleSheet } = ReactNative;

const StaticContainer = require('./StaticContainer');

const SceneComponent = (Props) => {
const {shouldUpdated, ...props, } = Props;
const {shouldUpdated, ...props } = Props;
return <View {...props}>
<StaticContainer shouldUpdate={shouldUpdated}>
{props.children}
Expand Down
207 changes: 36 additions & 171 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,13 @@ const SceneComponent = require('./SceneComponent');
const DefaultTabBar = require('./DefaultTabBar');
const ScrollableTabBar = require('./ScrollableTabBar');

const AnimatedViewPagerAndroid = Platform.OS === 'android' ?
Animated.createAnimatedComponent(ViewPagerAndroid) :
undefined;

const ScrollableTabView = createReactClass({
mixins: [TimerMixin, ],
statics: {
DefaultTabBar,
ScrollableTabBar,
},
scrollOnMountCalled: false,

propTypes: {
tabBarPosition: PropTypes.oneOf(['top', 'bottom', 'overlayTop', 'overlayBottom', ]),
Expand Down Expand Up @@ -60,49 +56,10 @@ const ScrollableTabView = createReactClass({
},

getInitialState() {
const containerWidth = Dimensions.get('window').width;
let scrollValue;
let scrollXIOS;
let positionAndroid;
let offsetAndroid;

if (Platform.OS === 'ios') {
scrollXIOS = new Animated.Value(this.props.initialPage * containerWidth);
const containerWidthAnimatedValue = new Animated.Value(containerWidth);
// Need to call __makeNative manually to avoid a native animated bug. See
// https://github.com/facebook/react-native/pull/14435
containerWidthAnimatedValue.__makeNative();
scrollValue = Animated.divide(scrollXIOS, containerWidthAnimatedValue);

const callListeners = this._polyfillAnimatedValue(scrollValue);
scrollXIOS.addListener(
({ value, }) => callListeners(value / this.state.containerWidth)
);
} else {
positionAndroid = new Animated.Value(this.props.initialPage);
offsetAndroid = new Animated.Value(0);
scrollValue = Animated.add(positionAndroid, offsetAndroid);

const callListeners = this._polyfillAnimatedValue(scrollValue);
let positionAndroidValue = this.props.initialPage;
let offsetAndroidValue = 0;
positionAndroid.addListener(({ value, }) => {
positionAndroidValue = value;
callListeners(positionAndroidValue + offsetAndroidValue);
});
offsetAndroid.addListener(({ value, }) => {
offsetAndroidValue = value;
callListeners(positionAndroidValue + offsetAndroidValue);
});
}

return {
currentPage: this.props.initialPage,
scrollValue,
scrollXIOS,
positionAndroid,
offsetAndroid,
containerWidth,
scrollValue: new Animated.Value(this.props.initialPage),
containerWidth: Dimensions.get('window').width,
sceneKeys: this.newSceneKeys({ currentPage: this.props.initialPage, }),
};
},
Expand All @@ -117,29 +74,10 @@ const ScrollableTabView = createReactClass({
}
},

componentWillUnmount() {
if (Platform.OS === 'ios') {
this.state.scrollXIOS.removeAllListeners();
} else {
this.state.positionAndroid.removeAllListeners();
this.state.offsetAndroid.removeAllListeners();
}
},

goToPage(pageNumber) {
if (Platform.OS === 'ios') {
const offset = pageNumber * this.state.containerWidth;
if (this.scrollView) {
this.scrollView.getNode().scrollTo({x: offset, y: 0, animated: !this.props.scrollWithoutAnimation, });
}
} else {
if (this.scrollView) {
if (this.props.scrollWithoutAnimation) {
this.scrollView.getNode().setPageWithoutAnimation(pageNumber);
} else {
this.scrollView.getNode().setPage(pageNumber);
}
}
const offset = pageNumber * this.state.containerWidth;
if (this.scrollView) {
this.scrollView.scrollTo({x: offset, y: 0, animated: !this.props.scrollWithoutAnimation, });
}

const currentPage = this.state.currentPage;
Expand Down Expand Up @@ -176,31 +114,6 @@ const ScrollableTabView = createReactClass({
return newKeys;
},

// Animated.add and Animated.divide do not currently support listeners so
// we have to polyfill it here since a lot of code depends on being able
// to add a listener to `scrollValue`. See https://github.com/facebook/react-native/pull/12620.
_polyfillAnimatedValue(animatedValue) {

const listeners = new Set();
const addListener = (listener) => {
listeners.add(listener);
};

const removeListener = (listener) => {
listeners.delete(listener);
};

const removeAllListeners = () => {
listeners.clear();
};

animatedValue.addListener = addListener;
animatedValue.removeListener = removeListener;
animatedValue.removeAllListeners = removeAllListeners;

return (value) => listeners.forEach(listener => listener({ value, }));
},

_shouldRenderSceneKey(idx, currentPageKey) {
let numOfSibling = this.props.prerenderingSiblingsNumber;
return (idx < (currentPageKey + numOfSibling + 1) &&
Expand All @@ -216,58 +129,30 @@ const ScrollableTabView = createReactClass({
},

renderScrollableContent() {
if (Platform.OS === 'ios') {
const scenes = this._composeScenes();
return <Animated.ScrollView
horizontal
pagingEnabled
automaticallyAdjustContentInsets={false}
contentOffset={{ x: this.props.initialPage * this.state.containerWidth, }}
ref={(scrollView) => { this.scrollView = scrollView; }}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { x: this.state.scrollXIOS, }, }, }, ],
{ useNativeDriver: true, listener: this._onScroll, }
)}
onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}
onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}
scrollEventThrottle={16}
scrollsToTop={false}
showsHorizontalScrollIndicator={false}
scrollEnabled={!this.props.locked}
directionalLockEnabled
alwaysBounceVertical={false}
keyboardDismissMode="on-drag"
{...this.props.contentProps}
>
{scenes}
</Animated.ScrollView>;
} else {
const scenes = this._composeScenes();
return <AnimatedViewPagerAndroid
key={this._children().length}
style={styles.scrollableContentAndroid}
initialPage={this.props.initialPage}
onPageSelected={this._updateSelectedPage}
keyboardDismissMode="on-drag"
scrollEnabled={!this.props.locked}
onPageScroll={Animated.event(
[{
nativeEvent: {
position: this.state.positionAndroid,
offset: this.state.offsetAndroid,
},
}, ],
{
useNativeDriver: true,
listener: this._onScroll,
},
)}
ref={(scrollView) => { this.scrollView = scrollView; }}
{...this.props.contentProps}
>
{scenes}
</AnimatedViewPagerAndroid>;
}
const scenes = this._composeScenes();
return <ScrollView
horizontal
pagingEnabled
automaticallyAdjustContentInsets={false}
contentOffset={{ x: this.props.initialPage * this.state.containerWidth, }}
ref={(scrollView) => { this.scrollView = scrollView; }}
onScroll={(e) => {
const offsetX = e.nativeEvent.contentOffset.x;
this._updateScrollValue(offsetX / this.state.containerWidth);
}}
onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}
onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}
scrollEventThrottle={16}
scrollsToTop={false}
showsHorizontalScrollIndicator={false}
scrollEnabled={!this.props.locked}
directionalLockEnabled
alwaysBounceVertical={false}
keyboardDismissMode="on-drag"
{...this.props.contentProps}
>
{scenes}
</ScrollView>;
},

_composeScenes() {
Expand Down Expand Up @@ -312,40 +197,20 @@ const ScrollableTabView = createReactClass({
});
},

_onScroll(e) {
if (Platform.OS === 'ios') {
const offsetX = e.nativeEvent.contentOffset.x;
if (offsetX === 0 && !this.scrollOnMountCalled) {
this.scrollOnMountCalled = true;
} else {
this.props.onScroll(offsetX / this.state.containerWidth);
}
} else {
const { position, offset, } = e.nativeEvent;
this.props.onScroll(position + offset);
}
_updateScrollValue(value) {
this.state.scrollValue.setValue(value);
this.props.onScroll(value);
},

_handleLayout(e) {
const { width, } = e.nativeEvent.layout;

if (!width || width <= 0 || Math.round(width) === Math.round(this.state.containerWidth)) {
return;
}

if (Platform.OS === 'ios') {
const containerWidthAnimatedValue = new Animated.Value(width);
// Need to call __makeNative manually to avoid a native animated bug. See
// https://github.com/facebook/react-native/pull/14435
containerWidthAnimatedValue.__makeNative();
scrollValue = Animated.divide(this.state.scrollXIOS, containerWidthAnimatedValue);
this.setState({ containerWidth: width, scrollValue, });
} else {
if (Math.round(width) !== Math.round(this.state.containerWidth)) {
this.setState({ containerWidth: width, });
this.requestAnimationFrame(() => {
this.goToPage(this.state.currentPage);
});
}
this.requestAnimationFrame(() => {
this.goToPage(this.state.currentPage);
});
},

_children(children = this.props.children) {
Expand Down