From bfacc7900e231abd4c026d6b4ce5a6d72c20f002 Mon Sep 17 00:00:00 2001 From: Vlad Potra Date: Tue, 18 Sep 2018 16:56:43 +0300 Subject: [PATCH] Fixed iOS flicker on swipe --- build/image-gallery.js | 126 ++++++++------------ example/app.js | 155 +++---------------------- src/ImageGallery.jsx | 132 ++++++++------------- styles/scss/image-gallery-no-icon.scss | 2 +- styles/scss/image-gallery.scss | 9 +- 5 files changed, 119 insertions(+), 305 deletions(-) diff --git a/build/image-gallery.js b/build/image-gallery.js index f55227c7..91540aee 100644 --- a/build/image-gallery.js +++ b/build/image-gallery.js @@ -80,7 +80,7 @@ var ImageGallery = function (_React$Component) { isTransitioning: nextIndex !== currentIndex, offsetPercentage: 0, style: { - transition: 'all ' + _this.props.slideDuration + 'ms ease-out' + transition: 'all ' + _this.props.slideDuration + 'ms ease' } }, _this._onSliding); } @@ -205,6 +205,7 @@ var ImageGallery = function (_React$Component) { var _this$state2 = _this.state, scrollingUpDown = _this$state2.scrollingUpDown, scrollingLeftRight = _this$state2.scrollingLeftRight; + var isRTL = _this.props.isRTL; if (scrollingUpDown) { // user stopped scrollingUpDown @@ -218,20 +219,19 @@ var ImageGallery = function (_React$Component) { if (!scrollingUpDown) { // don't swipe if user is scrolling - var side = deltaX > 0 ? 1 : -1; + var side = (deltaX > 0 ? 1 : -1) * (isRTL ? -1 : 1); //if it is RTL the direction is reversed _this._handleOnSwipedTo(side, isFlick); } }; _this._handleSwiping = function (e, deltaX, deltaY, delta) { - var swipingTransitionDuration = _this.props.swipingTransitionDuration; - - _this._setScrollDirection(deltaX, deltaY); var _this$state3 = _this.state, galleryWidth = _this$state3.galleryWidth, isTransitioning = _this$state3.isTransitioning, scrollingUpDown = _this$state3.scrollingUpDown; + var swipingTransitionDuration = _this.props.swipingTransitionDuration; + _this._setScrollDirection(deltaX, deltaY); if (!isTransitioning && !scrollingUpDown) { var side = deltaX < 0 ? 1 : -1; @@ -241,7 +241,7 @@ var ImageGallery = function (_React$Component) { } var swipingTransition = { - transition: 'transform ' + swipingTransitionDuration + 'ms ease-out' + transition: 'all ' + swipingTransitionDuration + 'ms ease' }; _this.setState({ @@ -373,10 +373,6 @@ var ImageGallery = function (_React$Component) { if (nextProps.lazyLoad && (!this.props.lazyLoad || this.props.items !== nextProps.items)) { this._lazyLoaded = []; } - - if (this.state.currentIndex >= nextProps.items.length) { - this.slideToIndex(0); - } } }, { key: 'componentDidUpdate', @@ -445,11 +441,7 @@ var ImageGallery = function (_React$Component) { this.setState({ isPlaying: true }); this._intervalId = window.setInterval(function () { if (!_this2.state.hovering) { - if (!_this2.props.infinite && !_this2._canSlideRight()) { - _this2.pause(); - } else { - _this2.slideToIndex(_this2.state.currentIndex + 1); - } + _this2.slideToIndex(_this2.state.currentIndex + 1); } }, Math.max(slideInterval, slideDuration)); @@ -615,12 +607,12 @@ var ImageGallery = function (_React$Component) { }, { key: '_canSlideLeft', value: function _canSlideLeft() { - return this.props.infinite || (this.props.isRTL ? this._canSlideNext() : this._canSlidePrevious()); + return this.props.isRTL ? this._canSlideNext() : this._canSlidePrevious(); } }, { key: '_canSlideRight', value: function _canSlideRight() { - return this.props.infinite || (this.props.isRTL ? this._canSlidePrevious() : this._canSlideNext()); + return this.props.isRTL ? this._canSlidePrevious() : this._canSlideNext(); } }, { key: '_canSlidePrevious', @@ -715,7 +707,7 @@ var ImageGallery = function (_React$Component) { break; } - if (this.props.items.length >= 3 && this.props.infinite) { + if (this.props.items.length >= 3) { if (index === 0 && currentIndex === this.props.items.length - 1) { // set first slide as right slide if were sliding right from last slide alignment = ' ' + RIGHT; @@ -801,21 +793,6 @@ var ImageGallery = function (_React$Component) { } return {}; } - }, { - key: '_shouldPushSlideOnInfiniteMode', - value: function _shouldPushSlideOnInfiniteMode(index) { - /* - Push(show) slide if slide is the current slide, and the next slide - OR - The slide is going more than 1 slide left, or right, but not going from - first to last and not going from last to first - There is an edge case where if you go to the first or last slide, when they're - not left, or right of each other they will try to catch up in the background - so unless were going from first to last or vice versa we don't want the first - or last slide to show up during our transition - */ - return !this._slideIsTransitioning(index) || this._ignoreIsTransitioning() && !this._isFirstOrLastSlide(index); - } }, { key: '_slideIsTransitioning', value: function _slideIsTransitioning(index) { @@ -860,40 +837,36 @@ var ImageGallery = function (_React$Component) { } }, { key: '_getSlideStyle', - value: function _getSlideStyle(index) { + value: function _getSlideStyle() { + return { + Width: this.state.galleryWidth + }; + } + }, { + key: '_getSlidesStyle', + value: function _getSlidesStyle() { var _state10 = this.state, currentIndex = _state10.currentIndex, offsetPercentage = _state10.offsetPercentage; - var _props2 = this.props, - infinite = _props2.infinite, - items = _props2.items, - useTranslate3D = _props2.useTranslate3D; + var useTranslate3D = this.props.useTranslate3D; - var baseTranslateX = -100 * currentIndex; - var totalSlides = items.length - 1; + // let translateX = currentIndex * -100 + offsetPercentage; - // calculates where the other slides belong based on currentIndex - var translateX = baseTranslateX + index * 100 + offsetPercentage; + var translateX = currentIndex * -100; - if (infinite && items.length > 2) { - if (currentIndex === 0 && index === totalSlides) { - // make the last slide the slide before the first - translateX = -100 + offsetPercentage; - } else if (currentIndex === totalSlides && index === 0) { - // make the first slide the slide after the last - translateX = 100 + offsetPercentage; - } - } - - // Special case when there are only 2 items with infinite on - if (infinite && items.length === 2) { - translateX = this._getTranslateXForTwoSlide(index); + if (!this._canSlideLeft() && offsetPercentage > 0) { + translateX += offsetPercentage / 3; + } else if (!this._canSlideRight() && offsetPercentage < 0) { + translateX += offsetPercentage / 3; + } else { + translateX += offsetPercentage; } + // console.log(translateX, offsetPercentage); - var translate = 'translate(' + translateX + '%, 0)'; + var translate = 'translate(' + translateX * this.state.galleryWidth + 'px, 0)'; if (useTranslate3D) { - translate = 'translate3d(' + translateX + '%, 0, 0)'; + translate = 'translate3d(' + translateX / 100 * this.state.galleryWidth + 'px, 0, 0)'; } return { @@ -908,9 +881,9 @@ var ImageGallery = function (_React$Component) { key: '_getThumbnailStyle', value: function _getThumbnailStyle() { var translate = void 0; - var _props3 = this.props, - useTranslate3D = _props3.useTranslate3D, - isRTL = _props3.isRTL; + var _props2 = this.props, + useTranslate3D = _props2.useTranslate3D, + isRTL = _props2.isRTL; var thumbsTranslate = this.state.thumbsTranslate; var verticalTranslateValue = isRTL ? thumbsTranslate * -1 : thumbsTranslate; @@ -945,10 +918,9 @@ var ImageGallery = function (_React$Component) { modalFullscreen = _state11.modalFullscreen, isPlaying = _state11.isPlaying, scrollingLeftRight = _state11.scrollingLeftRight; - var _props4 = this.props, - infinite = _props4.infinite, - preventDefaultTouchmoveEvent = _props4.preventDefaultTouchmoveEvent, - isRTL = _props4.isRTL; + var _props3 = this.props, + preventDefaultTouchmoveEvent = _props3.preventDefaultTouchmoveEvent, + isRTL = _props3.isRTL; var thumbnailStyle = this._getThumbnailStyle(); @@ -975,14 +947,12 @@ var ImageGallery = function (_React$Component) { _this5._lazyLoaded[index] = true; } - var slideStyle = _this5._getSlideStyle(index); - var slide = _react2.default.createElement( 'div', { key: index, className: 'image-gallery-slide' + alignment + originalClass, - style: _extends(slideStyle, _this5.state.style), + style: { 'width': _this5.state.galleryWidth }, onClick: _this5.props.onClick, onTouchMove: _this5.props.onTouchMove, onTouchEnd: _this5.props.onTouchEnd, @@ -994,15 +964,7 @@ var ImageGallery = function (_React$Component) { showItem ? renderItem(item) : _react2.default.createElement('div', { style: { height: '100%' } }) ); - if (infinite) { - // don't add some slides while transitioning to avoid background transitions - if (_this5._shouldPushSlideOnInfiniteMode(index)) { - slides.push(slide); - } - } else { - slides.push(slide); - } - + slides.push(slide); if (_this5.props.showThumbnails) { thumbnails.push(_react2.default.createElement( 'a', @@ -1067,12 +1029,18 @@ var ImageGallery = function (_React$Component) { }, _react2.default.createElement( 'div', - { className: 'image-gallery-slides' }, + { + className: 'image-gallery-slides', + style: _extends(this._getSlidesStyle(), this.state.style) + }, slides ) )] : _react2.default.createElement( 'div', - { className: 'image-gallery-slides' }, + { + className: 'image-gallery-slides', + style: this._getSlidesStyle() + }, slides ), this.props.showBullets && _react2.default.createElement( @@ -1171,7 +1139,6 @@ ImageGallery.propTypes = { showNav: _propTypes2.default.bool, autoPlay: _propTypes2.default.bool, lazyLoad: _propTypes2.default.bool, - infinite: _propTypes2.default.bool, showIndex: _propTypes2.default.bool, showBullets: _propTypes2.default.bool, showThumbnails: _propTypes2.default.bool, @@ -1220,7 +1187,6 @@ ImageGallery.defaultProps = { showNav: true, autoPlay: false, lazyLoad: false, - infinite: true, showIndex: false, showBullets: false, showThumbnails: true, diff --git a/example/app.js b/example/app.js index 11782de6..b3b7225b 100644 --- a/example/app.js +++ b/example/app.js @@ -168,7 +168,7 @@ class App extends React.Component { :
- + { item.description && +
this._imageGallery = i} items={this.images} - lazyLoad={false} - onClick={this._onImageClick.bind(this)} - onImageLoad={this._onImageLoad} - onSlide={this._onSlide.bind(this)} - onPause={this._onPause.bind(this)} - onScreenChange={this._onScreenChange.bind(this)} - onPlay={this._onPlay.bind(this)} - infinite={this.state.infinite} - showBullets={this.state.showBullets} + infinite={false} + showBullets={false} showFullscreenButton={this.state.showFullscreenButton && this.state.showGalleryFullscreenButton} - showPlayButton={this.state.showPlayButton && this.state.showGalleryPlayButton} - showThumbnails={this.state.showThumbnails} - showIndex={this.state.showIndex} + showPlayButton={false} + showThumbnails={false} + showIndex={false} showNav={this.state.showNav} - isRTL={this.state.isRTL} thumbnailPosition={this.state.thumbnailPosition} - slideDuration={parseInt(this.state.slideDuration)} - slideInterval={parseInt(this.state.slideInterval)} + slideDuration={400} + slideInterval={200} additionalClass="app-image-gallery" + preventDefaultTouchmoveEvent + stopPropagation + useTranslate3D + flickThreshold={1.0} /> +
+
-
- -
-

Settings

- -
    -
  • -
    - Play Interval - -
    -
  • - -
  • -
    - Slide Duration - -
    -
  • - -
  • -
    - Thumbnail Bar Position - -
    -
  • -
- -
    -
  • - - -
  • -
  • - - -
  • -
  • - - -
  • -
  • - - -
  • -
  • - - -
  • -
  • - - -
  • -
  • - - -
  • -
  • - - -
  • -
  • - - -
  • -
-
- -
); } } -ReactDOM.render(, document.getElementById('container')); +ReactDOM.render(, document.getElementById('container')); diff --git a/src/ImageGallery.jsx b/src/ImageGallery.jsx index 25c01962..6b5fb2e1 100644 --- a/src/ImageGallery.jsx +++ b/src/ImageGallery.jsx @@ -44,7 +44,6 @@ export default class ImageGallery extends React.Component { showNav: PropTypes.bool, autoPlay: PropTypes.bool, lazyLoad: PropTypes.bool, - infinite: PropTypes.bool, showIndex: PropTypes.bool, showBullets: PropTypes.bool, showThumbnails: PropTypes.bool, @@ -94,7 +93,6 @@ export default class ImageGallery extends React.Component { showNav: true, autoPlay: false, lazyLoad: false, - infinite: true, showIndex: false, showBullets: false, showThumbnails: true, @@ -175,10 +173,6 @@ export default class ImageGallery extends React.Component { (!this.props.lazyLoad || this.props.items !== nextProps.items)) { this._lazyLoaded = []; } - - if (this.state.currentIndex >= nextProps.items.length) { - this.slideToIndex(0); - } } componentDidUpdate(prevProps, prevState) { @@ -238,11 +232,7 @@ export default class ImageGallery extends React.Component { this.setState({isPlaying: true}); this._intervalId = window.setInterval(() => { if (!this.state.hovering) { - if (!this.props.infinite && !this._canSlideRight()) { - this.pause(); - } else { - this.slideToIndex(this.state.currentIndex + 1); - } + this.slideToIndex(this.state.currentIndex + 1); } }, Math.max(slideInterval, slideDuration)); @@ -348,7 +338,7 @@ export default class ImageGallery extends React.Component { isTransitioning: nextIndex !== currentIndex, offsetPercentage: 0, style: { - transition: `all ${this.props.slideDuration}ms ease-out` + transition: `all ${this.props.slideDuration}ms ease` } }, this._onSliding); } @@ -507,6 +497,7 @@ export default class ImageGallery extends React.Component { _handleOnSwiped = (e, deltaX, deltaY, isFlick) => { const { scrollingUpDown, scrollingLeftRight } = this.state; + const { isRTL } = this.props; if (scrollingUpDown) { // user stopped scrollingUpDown this.setState({ scrollingUpDown: false }); @@ -518,7 +509,7 @@ export default class ImageGallery extends React.Component { } if (!scrollingUpDown) { // don't swipe if user is scrolling - const side = deltaX > 0 ? 1 : -1; + const side = (deltaX > 0 ? 1 : -1) * (isRTL ? -1 : 1);//if it is RTL the direction is reversed this._handleOnSwipedTo(side, isFlick); } }; @@ -549,9 +540,9 @@ export default class ImageGallery extends React.Component { } _handleSwiping = (e, deltaX, deltaY, delta) => { + const { galleryWidth, isTransitioning, scrollingUpDown } = this.state; const { swipingTransitionDuration } = this.props; this._setScrollDirection(deltaX, deltaY); - const { galleryWidth, isTransitioning, scrollingUpDown } = this.state; if (!isTransitioning && !scrollingUpDown) { const side = deltaX < 0 ? 1 : -1; @@ -561,7 +552,7 @@ export default class ImageGallery extends React.Component { } const swipingTransition = { - transition: `transform ${swipingTransitionDuration}ms ease-out` + transition: `all ${swipingTransitionDuration}ms ease` }; this.setState({ @@ -579,13 +570,11 @@ export default class ImageGallery extends React.Component { } _canSlideLeft() { - return this.props.infinite || - (this.props.isRTL ? this._canSlideNext() : this._canSlidePrevious()); + return this.props.isRTL ? this._canSlideNext() : this._canSlidePrevious(); } _canSlideRight() { - return this.props.infinite || - (this.props.isRTL ? this._canSlidePrevious() : this._canSlideNext()); + return this.props.isRTL ? this._canSlidePrevious() : this._canSlideNext(); } _canSlidePrevious() { @@ -668,7 +657,7 @@ export default class ImageGallery extends React.Component { break; } - if (this.props.items.length >= 3 && this.props.infinite) { + if (this.props.items.length >= 3) { if (index === 0 && currentIndex === this.props.items.length - 1) { // set first slide as right slide if were sliding right from last slide alignment = ` ${RIGHT}`; @@ -745,22 +734,6 @@ export default class ImageGallery extends React.Component { return {}; } - _shouldPushSlideOnInfiniteMode(index) { - /* - Push(show) slide if slide is the current slide, and the next slide - OR - The slide is going more than 1 slide left, or right, but not going from - first to last and not going from last to first - - There is an edge case where if you go to the first or last slide, when they're - not left, or right of each other they will try to catch up in the background - so unless were going from first to last or vice versa we don't want the first - or last slide to show up during our transition - */ - return !this._slideIsTransitioning(index) || - (this._ignoreIsTransitioning() && !this._isFirstOrLastSlide(index)); - } - _slideIsTransitioning(index) { /* returns true if the gallery is transitioning and the index is not the @@ -795,43 +768,43 @@ export default class ImageGallery extends React.Component { notGoingFromLastToFirst; } - _getSlideStyle(index) { - const { currentIndex, offsetPercentage } = this.state; - const { infinite, items, useTranslate3D } = this.props; - const baseTranslateX = -100 * currentIndex; - const totalSlides = items.length - 1; + _getSlideStyle() { + return { + Width: this.state.galleryWidth + }; + } - // calculates where the other slides belong based on currentIndex - let translateX = baseTranslateX + (index * 100) + offsetPercentage; + _getSlidesStyle() { + const { currentIndex, offsetPercentage } = this.state; + const { useTranslate3D } = this.props; - if (infinite && items.length > 2) { - if (currentIndex === 0 && index === totalSlides) { - // make the last slide the slide before the first - translateX = -100 + offsetPercentage; - } else if (currentIndex === totalSlides && index === 0) { - // make the first slide the slide after the last - translateX = 100 + offsetPercentage; - } - } + // let translateX = currentIndex * -100 + offsetPercentage; + let translateX = currentIndex * -100; - // Special case when there are only 2 items with infinite on - if (infinite && items.length === 2) { - translateX = this._getTranslateXForTwoSlide(index); - } + if (!this._canSlideLeft() && offsetPercentage > 0) { + translateX += (offsetPercentage / 3); + } + else if (!this._canSlideRight() && offsetPercentage < 0) { + translateX += (offsetPercentage / 3); + } + else { + translateX += offsetPercentage; + } + // console.log(translateX, offsetPercentage); - let translate = `translate(${translateX}%, 0)`; + let translate = `translate(${translateX * this.state.galleryWidth }px, 0)`; - if (useTranslate3D) { - translate = `translate3d(${translateX}%, 0, 0)`; - } + if (useTranslate3D) { + translate = `translate3d(${(translateX / 100) * this.state.galleryWidth}px, 0, 0)`; + } - return { - WebkitTransform: translate, - MozTransform: translate, - msTransform: translate, - OTransform: translate, - transform: translate, - }; + return { + WebkitTransform: translate, + MozTransform: translate, + msTransform: translate, + OTransform: translate, + transform: translate, + }; } _getThumbnailStyle() { @@ -961,7 +934,6 @@ export default class ImageGallery extends React.Component { } = this.state; const { - infinite, preventDefaultTouchmoveEvent, isRTL, } = this.props; @@ -994,13 +966,11 @@ export default class ImageGallery extends React.Component { this._lazyLoaded[index] = true; } - let slideStyle = this._getSlideStyle(index); - const slide = (
); - if (infinite) { - // don't add some slides while transitioning to avoid background transitions - if (this._shouldPushSlideOnInfiniteMode(index)) { - slides.push(slide); - } - } else { - slides.push(slide); - } - + slides.push(slide); if (this.props.showThumbnails) { thumbnails.push( -
+
{slides}
] : -
+
{slides}
} diff --git a/styles/scss/image-gallery-no-icon.scss b/styles/scss/image-gallery-no-icon.scss index a4e55404..e7f3acdb 100644 --- a/styles/scss/image-gallery-no-icon.scss +++ b/styles/scss/image-gallery-no-icon.scss @@ -38,6 +38,7 @@ $ig-transparent: rgba(0, 0, 0, 0) !default; .image-gallery-content { position: relative; line-height: 0; + overflow: hidden; top: 0; &.fullscreen { @@ -127,7 +128,6 @@ $ig-transparent: rgba(0, 0, 0, 0) !default; .image-gallery-slides { line-height: 0; - overflow: hidden; position: relative; white-space: nowrap; } diff --git a/styles/scss/image-gallery.scss b/styles/scss/image-gallery.scss index 5006eb89..5a3b7e94 100644 --- a/styles/scss/image-gallery.scss +++ b/styles/scss/image-gallery.scss @@ -17,6 +17,7 @@ $ig-transparent: rgba(0, 0, 0, 0) !default; .image-gallery { @include vendor-prefix('user-select', none); -webkit-tap-highlight-color: $ig-transparent; + -webkit-transform: translate3d(0,0,0); &.fullscreen-modal { background: $ig-black; @@ -39,6 +40,7 @@ $ig-transparent: rgba(0, 0, 0, 0) !default; .image-gallery-content { position: relative; + overflow: hidden; line-height: 0; top: 0; @@ -198,17 +200,16 @@ $ig-transparent: rgba(0, 0, 0, 0) !default; .image-gallery-slides { line-height: 0; - overflow: hidden; position: relative; white-space: nowrap; + display: inline-flex; } .image-gallery-slide { background: $ig-white; left: 0; - position: absolute; + // position: absolute; top: 0; - width: 100%; &.center { position: relative; @@ -216,6 +217,8 @@ $ig-transparent: rgba(0, 0, 0, 0) !default; img { width: 100%; + -webkit-backface-visibility: hidden; + -webkit-transform-style: preserve-3d; } .image-gallery-description {