Clean up some grossness in ScrollResponder

Summary: Still gross but less gross.

Reviewed By: sebmarkbage

Differential Revision: D7107180

fbshipit-source-id: 31f1639a8f44e4ab247c338001a4a5c9b4b83cdf
This commit is contained in:
Sophie Alpert 2018-04-16 13:03:50 -07:00 committed by Facebook Github Bot
parent 8102e35271
commit a275eac56e
3 changed files with 54 additions and 34 deletions

View File

@ -23,7 +23,6 @@ const performanceNow = require('fbjs/lib/performanceNow');
const warning = require('fbjs/lib/warning');
const { ScrollViewManager } = require('NativeModules');
const { getInstanceFromNode } = require('ReactNativeComponentTree');
/**
* Mixin that can be integrated in order to handle scrolling that plays well
@ -114,15 +113,6 @@ type State = {
};
type Event = Object;
function isTagInstanceOfTextInput(tag) {
const instance = getInstanceFromNode(tag);
return instance && instance.viewConfig && (
instance.viewConfig.uiViewClassName === 'AndroidTextInput' ||
instance.viewConfig.uiViewClassName === 'RCTMultilineTextInputView' ||
instance.viewConfig.uiViewClassName === 'RCTSinglelineTextInputView'
);
}
const ScrollResponderMixin = {
mixins: [Subscribable.Mixin],
scrollResponderMixinGetInitialState: function(): State {
@ -196,17 +186,27 @@ const ScrollResponderMixin = {
* Invoke this from an `onStartShouldSetResponderCapture` event.
*/
scrollResponderHandleStartShouldSetResponderCapture: function(e: Event): boolean {
// First see if we want to eat taps while the keyboard is up
// The scroll view should receive taps instead of its descendants if:
// * it is already animating/decelerating
if (this.scrollResponderIsAnimating()) {
return true;
}
// * the keyboard is up, keyboardShouldPersistTaps is 'never' (the default),
// and a new touch starts with a non-textinput target (in which case the
// first tap should be sent to the scroll view and dismiss the keyboard,
// then the second tap goes to the actual interior view)
const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
const {keyboardShouldPersistTaps} = this.props;
const keyboardNeverPersistTaps = !keyboardShouldPersistTaps ||
keyboardShouldPersistTaps === 'never';
if (keyboardNeverPersistTaps &&
currentlyFocusedTextInput != null &&
!isTagInstanceOfTextInput(e.target)) {
currentlyFocusedTextInput != null
/* && !TextInputState.isTextInput(e.target) */) {
return true;
}
return this.scrollResponderIsAnimating();
return false;
},
/**

View File

@ -192,10 +192,6 @@ const DataDetectorTypes = [
const TextInput = createReactClass({
displayName: 'TextInput',
statics: {
/* TODO(brentvatne) docs are needed for this */
State: TextInputState,
},
propTypes: {
...ViewPropTypes,
@ -667,24 +663,30 @@ const TextInput = createReactClass({
componentDidMount: function() {
this._lastNativeText = this.props.value;
if (!this.context.focusEmitter) {
const tag = ReactNative.findNodeHandle(this._inputRef);
if (tag != null) {
// tag is null only in unit tests
TextInputState.registerInput(tag);
}
if (this.context.focusEmitter) {
this._focusSubscription = this.context.focusEmitter.addListener(
'focus',
el => {
if (this === el) {
this.requestAnimationFrame(this.focus);
} else if (this.isFocused()) {
this.blur();
}
},
);
if (this.props.autoFocus) {
this.context.onFocusRequested(this);
}
} else {
if (this.props.autoFocus) {
this.requestAnimationFrame(this.focus);
}
return;
}
this._focusSubscription = this.context.focusEmitter.addListener(
'focus',
el => {
if (this === el) {
this.requestAnimationFrame(this.focus);
} else if (this.isFocused()) {
this.blur();
}
},
);
if (this.props.autoFocus) {
this.context.onFocusRequested(this);
}
},
@ -693,6 +695,10 @@ const TextInput = createReactClass({
if (this.isFocused()) {
this.blur();
}
const tag = ReactNative.findNodeHandle(this._inputRef);
if (tag != null) {
TextInputState.unregisterInput(tag);
}
},
getChildContext(): ViewChildContext {

View File

@ -16,6 +16,8 @@
const Platform = require('Platform');
const UIManager = require('UIManager');
const inputs = new Set();
const TextInputState = {
/**
* Internal state
@ -68,7 +70,19 @@ const TextInputState = {
);
}
}
}
},
registerInput: function(textFieldID: number) {
inputs.add(textFieldID);
},
unregisterInput: function(textFieldID: number) {
inputs.delete(textFieldID);
},
isTextInput: function(textFieldID: number) {
return inputs.has(textFieldID);
},
};
module.exports = TextInputState;