[fix] ScrollView scrolling

Scrolling is broken by the patch that adds ResponderEvent support for
multi-input devices: 6a9212df40

By calling 'preventDefault' on every touch event, scroll events were
cancelled. This patch shifts the responsibility for calling
'preventDefault' to the 'View' event handler normalizer, and only on
touch events within the Responder system.

Fix #175
This commit is contained in:
Nicolas Gallagher
2016-07-29 14:00:35 -07:00
parent 8201906703
commit d54a84701a
4 changed files with 27 additions and 16 deletions
+1 -1
View File
@@ -117,7 +117,7 @@ const ScrollView = React.createClass({
_handleContentOnLayout(e: Object) {
const { width, height } = e.nativeEvent.layout
this.props.onContentSizeChange && this.props.onContentSizeChange(width, height)
this.props.onContentSizeChange(width, height)
},
render() {
+14 -5
View File
@@ -105,7 +105,7 @@ class View extends Component {
const normalizedEventHandlers = eventHandlerNames.reduce((handlerProps, handlerName) => {
const handler = this.props[handlerName]
if (typeof handler === 'function') {
handlerProps[handlerName] = this._normalizeEventForHandler(handler)
handlerProps[handlerName] = this._normalizeEventForHandler(handler, handlerName)
}
return handlerProps
}, {})
@@ -125,12 +125,21 @@ class View extends Component {
return createReactDOMComponent(props)
}
_normalizeEventForHandler(handler) {
const callback = (e) => {
_normalizeEventForHandler(handler, handlerName) {
// Browsers fire mouse events after touch events. This causes the
// ResponderEvents and their handlers to fire twice for Touchables.
// Auto-fix this issue by calling 'preventDefault' to cancel the mouse
// events.
const shouldCancelEvent = handlerName.indexOf('onResponder') === 0
return (e) => {
e.nativeEvent = normalizeNativeEvent(e.nativeEvent)
return handler(e)
const returnValue = handler(e)
if (shouldCancelEvent && e.cancelable) {
e.preventDefault()
}
return returnValue
}
return callback
}
}
@@ -45,12 +45,6 @@ ResponderTouchHistoryStore.recordTouchTrack = (topLevelType, nativeEvent) => {
if ((topLevelType === topMouseMove) && !ResponderTouchHistoryStore.touchHistory.touchBank.length) {
return
}
// Cancel mouse events that browsers fire after touch events
if (topLevelType === topTouchStart || topLevelType === topTouchMove || topLevelType === topTouchEnd) {
if (nativeEvent.target.getAttribute('href') !== undefined) {
nativeEvent.preventDefault()
}
}
const normalizedEvent = normalizeNativeEvent(nativeEvent)
originalRecordTouchTrack.call(ResponderTouchHistoryStore, topLevelType, normalizedEvent)
+12 -4
View File
@@ -7,6 +7,7 @@ const normalizeTouches = (touches = []) => Array.prototype.slice.call(touches).m
const locationY = touch.pageY - rect.top
return {
_normalized: true,
clientX: touch.clientX,
clientY: touch.clientY,
force: touch.force,
@@ -32,10 +33,13 @@ function normalizeTouchEvent(nativeEvent) {
const touches = normalizeTouches(nativeEvent.touches)
const event = {
_normalized: true,
changedTouches,
originalEvent: nativeEvent,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
preventDefault: nativeEvent.preventDefault.bind(nativeEvent),
stopImmediatePropagation: nativeEvent.stopImmediatePropagation.bind(nativeEvent),
stopPropagation: nativeEvent.stopPropagation.bind(nativeEvent),
target: nativeEvent.target,
// normalize the timestamp
// https://stackoverflow.com/questions/26177087/ios-8-mobile-safari-wrong-timestamp-on-touch-events
@@ -56,6 +60,7 @@ function normalizeTouchEvent(nativeEvent) {
function normalizeMouseEvent(nativeEvent) {
const touches = [{
_normalized: true,
clientX: nativeEvent.clientX,
clientY: nativeEvent.clientY,
force: nativeEvent.force,
@@ -70,13 +75,16 @@ function normalizeMouseEvent(nativeEvent) {
timestamp: Date.now()
}]
return {
_normalized: true,
changedTouches: touches,
identifier: touches[0].identifier,
locationX: nativeEvent.offsetX,
locationY: nativeEvent.offsetY,
originalEvent: nativeEvent,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
preventDefault: nativeEvent.preventDefault.bind(nativeEvent),
stopImmediatePropagation: nativeEvent.stopImmediatePropagation.bind(nativeEvent),
stopPropagation: nativeEvent.stopPropagation.bind(nativeEvent),
target: nativeEvent.target,
timestamp: touches[0].timestamp,
touches: (nativeEvent.type === 'mouseup') ? [] : touches
@@ -84,8 +92,8 @@ function normalizeMouseEvent(nativeEvent) {
}
function normalizeNativeEvent(nativeEvent) {
if (nativeEvent.originalEvent) { return nativeEvent }
const eventType = nativeEvent.type || (nativeEvent.originalEvent && nativeEvent.originalEvent.type) || ''
if (nativeEvent._normalized) { return nativeEvent }
const eventType = nativeEvent.type || ''
const mouse = eventType.indexOf('mouse') >= 0
return mouse ? normalizeMouseEvent(nativeEvent) : normalizeTouchEvent(nativeEvent)
}