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

ANDROID - Cannot set initial position #84

Open
kevinhimawan opened this issue Oct 2, 2019 · 5 comments
Open

ANDROID - Cannot set initial position #84

kevinhimawan opened this issue Oct 2, 2019 · 5 comments

Comments

@kevinhimawan
Copy link

kevinhimawan commented Oct 2, 2019

Hello i am trying set initial position of the slider, position={ numberPosition }. In IOS it works fine, but in ANDROID it always start from 0, suppose start from the value of numberPostion variable.

here is my code

Screenshot 2019-10-02 at 7 10 33 AM

@hblab-huongdv
Copy link

@kevinhimawan I think that It is an issue of scroll view on android. I resolved it by set timeout for scrollTo() function in the source code

@hthakore
Copy link

@kevinhimawan I think that It is an issue of scroll view on android. I resolved it by set timeout for scrollTo() function in the source code

can you provide code? how you managed

@hblab-huongdv
Copy link

@hthakore You can try to replace line 80 by this._ref && setTimeout(() => this._ref.scrollTo({ y: 0, x, animated }), 100);
Screen Shot 2020-06-01 at 15 56 23

@khanshamshad32
Copy link

khanshamshad32 commented Apr 19, 2021

try to update the state declaration expression at line 47

state = {
position: this.props.position || 0,
width: Dimensions.get('window').width,
onPositionChangedCalled: false,
interval: null,
};

@adnaanaeem
Copy link

adnaanaeem commented Oct 21, 2021

I fixed this issue wrt to @khanshamshad32 comment which will resolve the initial index issue. Thanks, Buddy.
Although it comes up with some other index issues on the slide.

So to fix the initial position issue and any other slider position issue needs to do this.
Just copy the ImageSlider.js file from the library and this as a component in your code and then do these changes
on line 47
Change this

 state = {
    position: 0,
    width: Dimensions.get('window').width,
    onPositionChangedCalled: false,
    interval: null,
  };

to this

 state = {
    position: this.props.position || 0,
    width: Dimensions.get('window').width,
    onPositionChangedCalled: false,
    interval: null,
  };

and also comment this if condition else you always receive the same index which you passed as initial. and don't forget to pass the initial index value now for slider with position = {index}

  _getPosition() {
    // if (typeof this.props.position === 'number') {
    //   return this.props.position;
    // }
    return this.state.position;
  }

here it whole class looks like this now

import React, { type, Node, Component } from 'react';
import {
  Image,
  View,
  ScrollView,
  TouchableHighlight,
  TouchableOpacity,
  Dimensions,
} from 'react-native';

import styles from '../../Smart/ImageSlider/style';

const reactNativePackage = require('react-native/package.json');
const splitVersion = reactNativePackage.version.split('.');
const majorVersion = +splitVersion[0];
const minorVersion = +splitVersion[1];

type Slide = {
  index: number,
  style?: any,
  width?: number,
  item?: any,
};

type PropsType = {
  images: string[],
  style?: any,
  loop?: boolean,
  loopBothSides?: boolean,
  autoPlayWithInterval?: number,
  position?: number,
  onPositionChanged?: number => void,
  onPress?: Object => void,
  customButtons?: (number, (number, animated?: boolean) => void) => Node,
  customSlide?: Slide => Node,
};

type StateType = {
  position: number,
  width: number,
  interval: any,
  onPositionChangedCalled: boolean,
};

class ImageSlider extends Component<PropsType, StateType> {
  state = {
    position: this.props.position || 0,
    width: Dimensions.get('window').width,
    onPositionChangedCalled: false,
    interval: null,
  };

  _ref = null;
  _panResponder = {};

  _onRef = (ref: any) => {
    this._ref = ref;
    if (ref && this.state.position !== this._getPosition()) {
      this._move(this._getPosition());
    }
  };

  // In iOS you can pop view by swiping left, with active ScrollView
  // you can't do that. This View on top of ScrollView enables call of
  // pop function.
  _popHelperView = () =>
    !this.props.loopBothSides &&
    this._getPosition() === 0 && (
      <View style={{ position: 'absolute', width: 50, height: '100%' }} />
    );

  _move = (index: number, animated: boolean = true) => {
    const isUpdating = index !== this._getPosition();
    const x = Dimensions.get('window').width * index;

    this._ref && this._ref.scrollTo({ y: 0, x, animated });

    this.setState({ position: index });

    if (
      isUpdating &&
      this.props.onPositionChanged &&
      index < this.props.images.length &&
      index > -1
    ) {
      this.props.onPositionChanged(index);
      this.setState({ onPositionChangedCalled: true });
    }

    this._setInterval();
  };

  _getPosition() {
    // if (typeof this.props.position === 'number') {
    //   return this.props.position;
    // }
    return this.state.position;
  }

  componentDidUpdate(prevProps: Object) {
    const { position } = this.props;

    if (position && prevProps.position !== position) {
      this._move(position);
    }
  }

  _clearInterval = () =>
    this.state.interval && clearInterval(this.state.interval);

  _setInterval = () => {
    this._clearInterval();
    const { autoPlayWithInterval, images, loop, loopBothSides } = this.props;

    if (autoPlayWithInterval) {
      this.setState({
        interval: setInterval(
          () =>
            this._move(
              !(loop || loopBothSides) &&
              this.state.position === images.length - 1
                ? 0
                : this.state.position + 1,
            ),
          autoPlayWithInterval,
        ),
      });
    }
  };

  _handleScroll = (event: Object) => {
    const { position, width } = this.state;
    const { loop, loopBothSides, images, onPositionChanged } = this.props;
    const { x } = event.nativeEvent.contentOffset;

    if (
      (loop || loopBothSides) &&
      x.toFixed() >= +(width * images.length).toFixed()
    ) {
      return this._move(0, false);
    } else if (loopBothSides && x.toFixed() <= +(-width).toFixed()) {
      return this._move(images.length - 1, false);
    }

    let newPosition = 0;

    if (position !== -1 && position !== images.length) {
      newPosition = Math.round(event.nativeEvent.contentOffset.x / width);
      this.setState({ position: newPosition });
    }

    if (
      onPositionChanged &&
      !this.state.onPositionChangedCalled &&
      newPosition < images.length &&
      newPosition > -1
    ) {
      onPositionChanged(newPosition);
    } else {
      this.setState({ onPositionChangedCalled: false });
    }

    this._setInterval();
  };

  componentWillMount() {
    this._setInterval();
  }

  componentWillUnmount() {
    this._clearInterval();
  }

  _onLayout = () => {
    this.setState({ width: Dimensions.get('window').width });
    this._move(this.state.position, false);
  };

  _renderImage = (image: any, index: number) => {
    const { width } = Dimensions.get('window');
    const { onPress, customSlide } = this.props;
    const offset = { marginLeft: index === -1 ? -width : 0 };
    const imageStyle = [styles.image, { width }, offset];

    if (customSlide) {
      return customSlide({ item: image, style: imageStyle, index, width });
    }

    const imageObject = typeof image === 'string' ? { uri: image } : image;

    const imageComponent = (
      <Image key={index} source={imageObject} style={[imageStyle]} />
    );

    if (onPress) {
      return (
        <TouchableOpacity
          key={index}
          style={[imageStyle, offset]}
          onPress={() => onPress && onPress({ image, index })}
          delayPressIn={200}
        >
          {imageComponent}
        </TouchableOpacity>
      );
    }

    return imageComponent;
  };

  // We make shure, that, when loop is active,
  // fake images at the begin and at the end of ScrollView
  // do not scroll.
  _scrollEnabled = (position: number) =>
    position !== -1 && position !== this.props.images.length;

  render() {
    const {
      onPress,
      customButtons,
      style,
      loop,
      images,
      loopBothSides,
    } = this.props;
    const position = this._getPosition();
    const scrollEnabled = this._scrollEnabled(position);

    return (
      <View style={[styles.container, style]} onLayout={this._onLayout}>
        <ScrollView
          onLayout={this._onLayout}
          ref={ref => this._onRef(ref)}
          onMomentumScrollEnd={this._handleScroll}
          scrollEventThrottle={16}
          pagingEnabled={true}
          bounces={loopBothSides}
          contentInset={loopBothSides ? { left: this.state.width } : {}}
          horizontal={true}
          scrollEnabled={scrollEnabled}
          showsHorizontalScrollIndicator={false}
          style={[styles.scrollViewContainer, style]}
        >
          {loopBothSides && this._renderImage(images[images.length - 1], -1)}
          {images.map(this._renderImage)}
          {(loop || loopBothSides) &&
            this._renderImage(images[0], images.length)}
        </ScrollView>
        {customButtons ? (
          customButtons(position, this._move)
        ) : (
          <View style={styles.buttons}>
            {this.props.images.map((image, index) => (
              <TouchableHighlight
                key={index}
                underlayColor="#ccc"
                onPress={() => this._move(index)}
                style={[
                  styles.button,
                  position === index && styles.buttonSelected,
                ]}
              >
                <View />
              </TouchableHighlight>
            ))}
          </View>
        )}
        {this._popHelperView()}
      </View>
    );
  }
}

export default ImageSlider;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants