Skip to content

Commit

Permalink
Merge pull request taofed#5 from cpunion/animated-scroll
Browse files Browse the repository at this point in the history
ScrollView scrolls with animation
  • Loading branch information
flyskywhy authored Jun 30, 2017
2 parents c536846 + 3aa60cc commit e093909
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 17 deletions.
10 changes: 7 additions & 3 deletions Libraries/ListView/ScrollResponder.web.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import warning from 'fbjs/lib/warning';
import animatedScrollTo from '../Utilties/animatedScrollTo';

/**
* Mixin that can be integrated in order to handle scrolling that plays well
Expand Down Expand Up @@ -93,6 +94,7 @@ import warning from 'fbjs/lib/warning';
*/

const IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16;
const ANIMATION_DURATION_MS = 300;

type State = {
isTouching: boolean;
Expand Down Expand Up @@ -351,7 +353,9 @@ let ScrollResponderMixin = {
*/
scrollResponderScrollTo: function(offsetX: number, offsetY: number) {
// TODO: Add scroll animation
this.scrollResponderScrollWithouthAnimationTo(offsetX, offsetY);
let node = ReactDOM.findDOMNode(this);

animatedScrollTo(node, {y: offsetY, x: offsetX}, ANIMATION_DURATION_MS);
},

/**
Expand All @@ -361,8 +365,8 @@ let ScrollResponderMixin = {
scrollResponderScrollWithouthAnimationTo: function(offsetX: number, offsetY: number) {

let node = ReactDOM.findDOMNode(this);
node.offsetX = offsetX;
node.offsetY = offsetY;
node.scrollLeft = offsetX;
node.scrollTop = offsetY;
},

/**
Expand Down
20 changes: 6 additions & 14 deletions Libraries/ScrollView/ScrollView.web.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,18 @@ class ScrollView extends Component {
return this.refs[INNERVIEW];
}

scrollTo(opts) {
scrollTo(opts: { x?: number, y?: number, animated?: boolean }) {
// $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
// this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0);
if (typeof opts === 'number') {
opts = { y: opts, x: arguments[1] };
}

this.scrollWithoutAnimationTo(opts.y, opts.x);
}

scrollWithoutAnimationTo(destY?: number, destX?: number) {
// $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
// this.getScrollResponder().scrollResponderScrollWithouthAnimationTo(
// destX || 0,
// destY || 0,
// );

this._scrollViewDom = ReactDOM.findDOMNode(this.refs[SCROLLVIEW]);
this._scrollViewDom.scrollTop = destY || 0;
this._scrollViewDom.scrollLeft = destX || 0;
if (opts.animated) {
this.getScrollResponder().scrollResponderScrollTo(opts.x || 0, opts.y || 0);
} else {
this.getScrollResponder().scrollResponderScrollWithouthAnimationTo(opts.x || 0, opts.y || 0);
}
}

handleScroll(e: Event) {
Expand Down
57 changes: 57 additions & 0 deletions Libraries/Utilties/animatedScrollTo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Modified from https://github.com/madebysource/animated-scrollto/blob/master/animatedScrollTo.js

(function (window) {
var requestAnimFrame = (function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1000/60);};})();

var easeInOutQuad = function (t, b, c, d) {
t /= d/2;
if (t < 1) return c/2*t*t + b;
t--;
return -c/2 * (t*(t-2) - 1) + b;
};

var animatedScrollTo = function (element, to, duration, callback) {
var startY = element.scrollTop;
var startX = element.scrollLeft;
var changeY = to.y - startY;
var changeX = to.x - startX;
var animationStart = +new Date();
var animating = true;
var lastposX = null;
var lastposY = null;

var animateScroll = function() {
if (!animating) {
return;
}
requestAnimFrame(animateScroll);
var now = +new Date();
var valY = Math.floor(easeInOutQuad(now - animationStart, startY, changeY, duration));
var valX = Math.floor(easeInOutQuad(now - animationStart, startX, changeX, duration));

// If last position is not element's scroll position, maybe user was scrolled.
if (lastposY === null ||
(lastposY === element.scrollTop && lastposX === element.scrollLeft)) {
lastposY = valY;
lastposX = valX;
element.scrollTop = valY;
element.scrollLeft = valX;
} else {
animating = false;
}
if (now > animationStart + duration) {
element.scrollTop = to.y;
element.scrollLeft = to.x;
animating = false;
if (callback) { callback(); }
}
};
requestAnimFrame(animateScroll);
};

if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = animatedScrollTo;
} else {
window.animatedScrollTo = animatedScrollTo;
}
})(window);

0 comments on commit e093909

Please sign in to comment.