React-native-swiper: Swiper Don't Work in Modal at Android

Created on 9 Jun 2017  ·  12Comments  ·  Source: leecade/react-native-swiper

if I press Android HardwareHomeKey let the app back Backstage then open my app, swiper lost sliding effect。
My code:

'use strict';
import React, {
Component
} from 'react';
import {
View,
Text,
Dimensions,
Image,
TouchableOpacity,
Modal,
StyleSheet,
} from 'react-native';
const {
width,
height
} = Dimensions.get('window');
const imageSource = [
require('../images/guide_page1.png'),
require('../images/guide_page2.png'),
require('../images/guide_page3.png'),
require('../images/guide_page4.png'),
];
import { RatiocalWidth, RatiocalHeight, RatiocalFontSize } from '../style';
import { toastShort } from './ToastUtil';
import Swiper from 'react-native-swiper';

export default class WelcomePage extends Component {
constructor(props) {
super(props);
this.state = {
isShowCircleDot: true,
}
this._renderImg = this._renderImg.bind(this);
}

_renderImg() {
    const { _click } = this.props
    let imageSource = [
        require('../images/guide_page1.png'),
        require('../images/guide_page2.png'),
        require('../images/guide_page3.png'),
        require('../images/guide_page4.png'),
    ];
    var imageViews = [];
    for (var i = 0; i < imageSource.length; i++) {
        if (i == imageSource.length - 1) {
            imageViews.push(
                <Image
                    key={i}
                    style={styles.swiperImage}
                    source={imageSource[i]} >
                    <TouchableOpacity style={styles.btnEsperience} onPress={() => _click()} >
                        <Text style={styles.btnText}>
                            马上体验
                        </Text>
                    </TouchableOpacity>
                </Image>
            );
        }
        else {
            imageViews.push(
                <Image
                    key={i}
                    style={styles.swiperImage}
                    source={imageSource[i]}
                    />
            );
        }
    }
    return imageViews
}

_renderImage(val, i) {
    const { _click } = this.props
    return (
        <View key={i} style={{ flex: 1, flexDirection: 'column' }}>
            <Image
                style={styles.swiperImage}
                source={imageSource[i]} >
                {
                    i === imageSource.length - 1 ?
                        <TouchableOpacity style={styles.btnEsperience} onPress={() => _click()} >
                            <Text style={styles.btnText}>
                                马上体验
                        </Text>
                        </TouchableOpacity>
                        :
                        null
                }
            </Image>
        </View>
    );

}

_onMomentumScrollEnd(e, state, context) {
    if (state.index == 3) {
        this.setState({
            isShowCircleDot: false,
        })
    }else {
        this.setState({
            isShowCircleDot: true,
        })
    }
}

render() {
    const { visible } = this.props
    return (
        <Modal
            animationType={'fade'}
            visible={visible}
            transparent
            onRequestClose={(state) => { } } >
            <View style={styles.backgroudView}>
                <Swiper
                    loop={false}
                    autoplay={false}
                    showsButtons={false}
                    showsPagination={false}
                    width={width}
                    height={height}
                    index={0}
                    onMomentumScrollEnd={(e, state, context) => this._onMomentumScrollEnd(e, state, context)}>
                    {
                        imageSource.map((val, i) => this._renderImage(val, i))
                    }
                </Swiper>
            </View>
        </Modal >
    );
}

}
const styles = StyleSheet.create({
backgroudView: {
flexGrow: 1,
backgroundColor: '#ffffff',
},
swiperImage: {
width: width,
height: height,
/**
* contain 根据图片本身的宽高比
* cover,
* stretch
*/
resizeMode: Image.resizeMode.stretch,
justifyContent: 'flex-end',
},
btnEsperience: {
marginBottom: RatiocalHeight(160),
width: width / 2,
height: RatiocalHeight(100),
borderColor: '#1D9FF9',
borderRadius: 7,
borderWidth: 1,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
},
btnText: {
fontSize: RatiocalFontSize(36),
textAlign: 'center',
color: '#1D9FF9',
},
});

Most helpful comment

I had to add a delay to get mine to work, but yes @WhiteClouds2009 it works!

  constructor(props) {
    super(props);
    this.state = { showSwiper: false };
  }

  componentDidMount() {
    // Must use this 100-ms delayed swiper workaround to render on Android properly
    setTimeout(() => {
      this.setState({showSwiper: true});
    }, 100);
  }

  render() {
    var exampleSwiper = (
      <Swiper activeDotColor={'white'} loop={false} >
        <View style={{width: 100, height: 100, backgroundColor: 'white'}} />
        <View style={{width: 100, height: 100, backgroundColor: 'white'}} />
        <View style={{width: 100, height: 100, backgroundColor: 'white'}} />
      </Swiper>
    );
    return (
      <Modal presentationStyle={'overFullScreen'}>
        {this.state.showSwiper ? exampleSwiper : null}
      </Modal>
    );
  }

All 12 comments

I had the same problem, and do:
1.Set a state param like this.state = { loadSwiper = false }
2.When componentDidMount, put this.setState({loadSwiper = true})
3.At the render method, {loadSwiper? : null}

In summary, you just re-render the Swiper after componentDidMount

@WhiteClouds2009 works for me, thanks

you can call Swiper after Modal is shown

I had to add a delay to get mine to work, but yes @WhiteClouds2009 it works!

  constructor(props) {
    super(props);
    this.state = { showSwiper: false };
  }

  componentDidMount() {
    // Must use this 100-ms delayed swiper workaround to render on Android properly
    setTimeout(() => {
      this.setState({showSwiper: true});
    }, 100);
  }

  render() {
    var exampleSwiper = (
      <Swiper activeDotColor={'white'} loop={false} >
        <View style={{width: 100, height: 100, backgroundColor: 'white'}} />
        <View style={{width: 100, height: 100, backgroundColor: 'white'}} />
        <View style={{width: 100, height: 100, backgroundColor: 'white'}} />
      </Swiper>
    );
    return (
      <Modal presentationStyle={'overFullScreen'}>
        {this.state.showSwiper ? exampleSwiper : null}
      </Modal>
    );
  }

Even with this workaround, the issue is still happening. Even tried large delay like 2 seconds.
Does this still have no solution?

+1
someone please have a look at this

+1

I have this problem when changing the underlying data and popping back to a screen (using react-native-navigator) which contains the Swiper. On the first load if works as expected, but later it doesn't.

Does anyone happen to know what is then root cause , so we can figure out a solution other than workarounds for this problem ?

I think I may have solved this particular problem. I stared with the above 'setTimeOut' solution, then saw that Modal has an event called onShow that is called when the modal has finished it's animation, as such the following seems to work or me:

setSwiperVisible(visible){
    this.setState({showSwiper: visible});
  }
render(){
  return(
  <Modal 
    visible={this.state.modalVisible}
    onShow={() => {
      this.setSwiperVisible(true)
    }}
  >
    {this.state.showSwiper && 
      <Swiper>
          ...
      </Swiper>
    }
  </Modal>
  )
}

Now there's no dependence on timers being right! Let me know if it works for you to.

EDIT
Scratch that, only works on the first showing :(

As suggested by @alangumer, this PR solved the problem for me: #761

Hi, is there any update regarding this issue?

Is there any idea why it needs some time delay to show the swiper _again_? I mean, is it like the rendering part that took so slow or anything else?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wrannaman picture wrannaman  ·  3Comments

ghost picture ghost  ·  3Comments

tokict picture tokict  ·  3Comments

JonasOmdal picture JonasOmdal  ·  3Comments

hadrienbbt picture hadrienbbt  ·  3Comments