leecade / react-native-swiper

The best Swiper component for React Native.
MIT License
10.37k stars 2.35k forks source link

Swiper Don't Work in Modal at Android #435

Open hongwc opened 7 years ago

hongwc commented 7 years ago

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, /**

WhiteClouds2009 commented 7 years ago

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? <Swiper ...> : null}

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

pein892 commented 7 years ago

@WhiteClouds2009 works for me, thanks

wenkangzhou commented 6 years ago

you can call Swiper after Modal is shown

sunweiyang commented 6 years ago

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>
    );
  }
Andrfas commented 6 years ago

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

appielife commented 6 years ago

+1 someone please have a look at this

nartjie101 commented 6 years ago

+1

hugows commented 6 years ago

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.

andy-zhang-guohua commented 6 years ago

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

booleanBoy commented 6 years ago

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 :(

booleanBoy commented 6 years ago

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

martabacc commented 5 years ago

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?