mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-06-01 10:07:35 +00:00
[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:
@@ -117,7 +117,7 @@ const ScrollView = React.createClass({
|
|||||||
|
|
||||||
_handleContentOnLayout(e: Object) {
|
_handleContentOnLayout(e: Object) {
|
||||||
const { width, height } = e.nativeEvent.layout
|
const { width, height } = e.nativeEvent.layout
|
||||||
this.props.onContentSizeChange && this.props.onContentSizeChange(width, height)
|
this.props.onContentSizeChange(width, height)
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class View extends Component {
|
|||||||
const normalizedEventHandlers = eventHandlerNames.reduce((handlerProps, handlerName) => {
|
const normalizedEventHandlers = eventHandlerNames.reduce((handlerProps, handlerName) => {
|
||||||
const handler = this.props[handlerName]
|
const handler = this.props[handlerName]
|
||||||
if (typeof handler === 'function') {
|
if (typeof handler === 'function') {
|
||||||
handlerProps[handlerName] = this._normalizeEventForHandler(handler)
|
handlerProps[handlerName] = this._normalizeEventForHandler(handler, handlerName)
|
||||||
}
|
}
|
||||||
return handlerProps
|
return handlerProps
|
||||||
}, {})
|
}, {})
|
||||||
@@ -125,12 +125,21 @@ class View extends Component {
|
|||||||
return createReactDOMComponent(props)
|
return createReactDOMComponent(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
_normalizeEventForHandler(handler) {
|
_normalizeEventForHandler(handler, handlerName) {
|
||||||
const callback = (e) => {
|
// 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)
|
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) {
|
if ((topLevelType === topMouseMove) && !ResponderTouchHistoryStore.touchHistory.touchBank.length) {
|
||||||
return
|
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)
|
const normalizedEvent = normalizeNativeEvent(nativeEvent)
|
||||||
originalRecordTouchTrack.call(ResponderTouchHistoryStore, topLevelType, normalizedEvent)
|
originalRecordTouchTrack.call(ResponderTouchHistoryStore, topLevelType, normalizedEvent)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const normalizeTouches = (touches = []) => Array.prototype.slice.call(touches).m
|
|||||||
const locationY = touch.pageY - rect.top
|
const locationY = touch.pageY - rect.top
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
_normalized: true,
|
||||||
clientX: touch.clientX,
|
clientX: touch.clientX,
|
||||||
clientY: touch.clientY,
|
clientY: touch.clientY,
|
||||||
force: touch.force,
|
force: touch.force,
|
||||||
@@ -32,10 +33,13 @@ function normalizeTouchEvent(nativeEvent) {
|
|||||||
const touches = normalizeTouches(nativeEvent.touches)
|
const touches = normalizeTouches(nativeEvent.touches)
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
|
_normalized: true,
|
||||||
changedTouches,
|
changedTouches,
|
||||||
originalEvent: nativeEvent,
|
|
||||||
pageX: nativeEvent.pageX,
|
pageX: nativeEvent.pageX,
|
||||||
pageY: nativeEvent.pageY,
|
pageY: nativeEvent.pageY,
|
||||||
|
preventDefault: nativeEvent.preventDefault.bind(nativeEvent),
|
||||||
|
stopImmediatePropagation: nativeEvent.stopImmediatePropagation.bind(nativeEvent),
|
||||||
|
stopPropagation: nativeEvent.stopPropagation.bind(nativeEvent),
|
||||||
target: nativeEvent.target,
|
target: nativeEvent.target,
|
||||||
// normalize the timestamp
|
// normalize the timestamp
|
||||||
// https://stackoverflow.com/questions/26177087/ios-8-mobile-safari-wrong-timestamp-on-touch-events
|
// https://stackoverflow.com/questions/26177087/ios-8-mobile-safari-wrong-timestamp-on-touch-events
|
||||||
@@ -56,6 +60,7 @@ function normalizeTouchEvent(nativeEvent) {
|
|||||||
|
|
||||||
function normalizeMouseEvent(nativeEvent) {
|
function normalizeMouseEvent(nativeEvent) {
|
||||||
const touches = [{
|
const touches = [{
|
||||||
|
_normalized: true,
|
||||||
clientX: nativeEvent.clientX,
|
clientX: nativeEvent.clientX,
|
||||||
clientY: nativeEvent.clientY,
|
clientY: nativeEvent.clientY,
|
||||||
force: nativeEvent.force,
|
force: nativeEvent.force,
|
||||||
@@ -70,13 +75,16 @@ function normalizeMouseEvent(nativeEvent) {
|
|||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
}]
|
}]
|
||||||
return {
|
return {
|
||||||
|
_normalized: true,
|
||||||
changedTouches: touches,
|
changedTouches: touches,
|
||||||
identifier: touches[0].identifier,
|
identifier: touches[0].identifier,
|
||||||
locationX: nativeEvent.offsetX,
|
locationX: nativeEvent.offsetX,
|
||||||
locationY: nativeEvent.offsetY,
|
locationY: nativeEvent.offsetY,
|
||||||
originalEvent: nativeEvent,
|
|
||||||
pageX: nativeEvent.pageX,
|
pageX: nativeEvent.pageX,
|
||||||
pageY: nativeEvent.pageY,
|
pageY: nativeEvent.pageY,
|
||||||
|
preventDefault: nativeEvent.preventDefault.bind(nativeEvent),
|
||||||
|
stopImmediatePropagation: nativeEvent.stopImmediatePropagation.bind(nativeEvent),
|
||||||
|
stopPropagation: nativeEvent.stopPropagation.bind(nativeEvent),
|
||||||
target: nativeEvent.target,
|
target: nativeEvent.target,
|
||||||
timestamp: touches[0].timestamp,
|
timestamp: touches[0].timestamp,
|
||||||
touches: (nativeEvent.type === 'mouseup') ? [] : touches
|
touches: (nativeEvent.type === 'mouseup') ? [] : touches
|
||||||
@@ -84,8 +92,8 @@ function normalizeMouseEvent(nativeEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeNativeEvent(nativeEvent) {
|
function normalizeNativeEvent(nativeEvent) {
|
||||||
if (nativeEvent.originalEvent) { return nativeEvent }
|
if (nativeEvent._normalized) { return nativeEvent }
|
||||||
const eventType = nativeEvent.type || (nativeEvent.originalEvent && nativeEvent.originalEvent.type) || ''
|
const eventType = nativeEvent.type || ''
|
||||||
const mouse = eventType.indexOf('mouse') >= 0
|
const mouse = eventType.indexOf('mouse') >= 0
|
||||||
return mouse ? normalizeMouseEvent(nativeEvent) : normalizeTouchEvent(nativeEvent)
|
return mouse ? normalizeMouseEvent(nativeEvent) : normalizeTouchEvent(nativeEvent)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user