Fix Android flash and iOS juttering

Summary:
Before:
- Android had the slideout row flash upon render due to it being rendered first
- iOS had the left side of each row load first, then rerender to show entire row when `scrollViewWidth` is available

Reason:
- Android was loading the slideout view first without an opacity check
- iOS was loading the swipeable view with width 0 first then stretching to `scrollViewWidth` when it was available via `onLayout`

Fix:
Render swipeable view with `flex: 1` then render slideout view

Reviewed By: fkgozali

Differential Revision: D3321466

fbshipit-source-id: 92a3b5e22034e06d05986ddb8c348796bafbbf34
This commit is contained in:
Fred Liu 2016-05-19 21:39:58 -07:00 committed by Facebook Github Bot 4
parent 830197847a
commit 62e588bece
1 changed files with 23 additions and 42 deletions

View File

@ -25,7 +25,6 @@
const Animated = require('Animated');
const PanResponder = require('PanResponder');
const Platform = require('Platform');
const React = require('React');
const StyleSheet = require('StyleSheet');
const View = require('View');
@ -49,11 +48,7 @@ const SwipeableRow = React.createClass({
propTypes: {
isOpen: PropTypes.bool,
/**
* Left position of the maximum open swipe. If unspecified, swipe will open
* fully to the left
*/
maxSwipeDistance: PropTypes.number,
maxSwipeDistance: PropTypes.number.isRequired,
onOpen: PropTypes.func,
onSwipeEnd: PropTypes.func.isRequired,
onSwipeStart: PropTypes.func.isRequired,
@ -79,17 +74,13 @@ const SwipeableRow = React.createClass({
* component A to be transparent until component B is loaded.
*/
isSwipeableViewRendered: false,
/**
* scrollViewWidth can change based on orientation, thus it's stored as a
* state variable. This means all styles depending on it will be inline
*/
scrollViewWidth: 0,
};
},
getDefaultProps(): Object {
return {
isOpen: false,
maxSwipeDistance: 0,
onSwipeEnd: emptyFunction,
onSwipeStart: emptyFunction,
swipeThreshold: 30,
@ -122,26 +113,26 @@ const SwipeableRow = React.createClass({
},
render(): ReactElement {
const slideoutStyle = [styles.slideOutContainer];
if (Platform.OS === 'ios') {
slideoutStyle.push({opacity: this.state.isSwipeableViewRendered ? 1 : 0});
// The view hidden behind the main view
let slideOutView;
if (this.state.isSwipeableViewRendered) {
slideOutView = (
<View style={styles.slideOutContainer}>
{this.props.slideoutView}
</View>
);
}
// The view hidden behind the main view
const slideOutView = (
<View style={slideoutStyle}>
{this.props.slideoutView}
</View>
);
// The swipable item
// The swipeable item
const swipeableView = (
<Animated.View
onLayout={this._onSwipeableViewLayout}
style={{
transform: [{translateX: this.state.currentLeft}],
width: this.state.scrollViewWidth,
}}>
style={[
styles.swipeableContainer,
{
transform: [{translateX: this.state.currentLeft}],
},
]}>
{this.props.children}
</Animated.View>
);
@ -149,8 +140,7 @@ const SwipeableRow = React.createClass({
return (
<View
{...this._panResponder.panHandlers}
style={styles.container}
onLayout={this._onLayoutChange}>
style={styles.container}>
{slideOutView}
{swipeableView}
</View>
@ -158,7 +148,7 @@ const SwipeableRow = React.createClass({
},
_onSwipeableViewLayout(event: Object): void {
if (!this._isSwipeableViewRendered && this.state.scrollViewWidth !== 0) {
if (!this.state.isSwipeableViewRendered) {
this.setState({
isSwipeableViewRendered: true,
});
@ -198,10 +188,7 @@ const SwipeableRow = React.createClass({
},
_animateToOpenPosition(): void {
const toValue = this.props.maxSwipeDistance
? -this.props.maxSwipeDistance
: -this.state.scrollViewWidth;
this._animateTo(toValue);
this._animateTo(-this.props.maxSwipeDistance);
},
_animateToClosedPosition(): void {
@ -235,15 +222,6 @@ const SwipeableRow = React.createClass({
this.props.onSwipeEnd();
},
_onLayoutChange(event: Object): void {
const width = event.nativeEvent.layout.width;
if (width && width !== this.state.scrollViewWidth) {
this.setState({
scrollViewWidth: width,
});
}
},
});
const styles = StyleSheet.create({
@ -259,6 +237,9 @@ const styles = StyleSheet.create({
right: 0,
top: 0,
},
swipeableContainer: {
flex: 1,
},
});
module.exports = SwipeableRow;