Skip to content

Commit

Permalink
Don't dismiss keyboard when tapping another text input
Browse files Browse the repository at this point in the history
Summary:
When using text inputs inside a ScrollView with `keyboardShouldPersistTaps=false` (default behavior) tapping another text input dismisses the keyboard instead of keeping it open and focusing the new text input which I think is the better and expected behavior.

See #10628 for more discussion about that. Note that this affects nothing but the behavior with text inputs unlike #10628.

cc satya164 MaxLap ericvicenti
Closes #10887

Differential Revision: D4178474

Pulled By: ericvicenti

fbshipit-source-id: 0c62ea2fac0017d559d1f8674b0a686a5e1b3d2d
  • Loading branch information
janicduplessis authored and Facebook Github Bot committed Nov 25, 2016
1 parent 0e55f5b commit 552c601
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
14 changes: 12 additions & 2 deletions Libraries/Components/ScrollResponder.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var Subscribable = require('Subscribable');
var TextInputState = require('TextInputState');
var UIManager = require('UIManager');

var { getInstanceFromNode } = require('ReactNativeComponentTree');
var { ScrollViewManager } = require('NativeModules');

var invariant = require('fbjs/lib/invariant');
Expand Down Expand Up @@ -112,6 +113,15 @@ type State = {
};
type Event = Object;

function isTagInstanceOfTextInput(tag) {
var instance = getInstanceFromNode(tag);
return instance && instance.viewConfig && (
instance.viewConfig.uiViewClassName === 'AndroidTextInput' ||
instance.viewConfig.uiViewClassName === 'RCTTextView' ||
instance.viewConfig.uiViewClassName === 'RCTTextField'
);
}

var ScrollResponderMixin = {
mixins: [Subscribable.Mixin],
scrollResponderMixinGetInitialState: function(): State {
Expand Down Expand Up @@ -172,7 +182,7 @@ var ScrollResponderMixin = {
* that *doesn't* give priority to nested views (hence the capture phase):
*
* - Currently animating.
* - Tapping anywhere that is not the focused input, while the keyboard is
* - Tapping anywhere that is not a text input, while the keyboard is
* up (which should dismiss the keyboard).
*
* Invoke this from an `onStartShouldSetResponderCapture` event.
Expand All @@ -182,7 +192,7 @@ var ScrollResponderMixin = {
var currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
if (!this.props.keyboardShouldPersistTaps &&
currentlyFocusedTextInput != null &&
e.target !== currentlyFocusedTextInput) {
!isTagInstanceOfTextInput(e.target)) {
return true;
}
return this.scrollResponderIsAnimating();
Expand Down
4 changes: 2 additions & 2 deletions Libraries/ReactNative/requireNativeComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ function requireNativeComponent(
return createReactNativeComponentClass(viewConfig);
}

var TypeToDifferMap = {
const TypeToDifferMap = {
// iOS Types
CATransform3D: matricesDiffer,
CGPoint: pointsDiffer,
Expand All @@ -115,7 +115,7 @@ function processColorArray(colors: []): [] {
return colors && colors.map(processColor);
}

var TypeToProcessorMap = {
const TypeToProcessorMap = {
// iOS Types
CGColor: processColor,
CGColorArray: processColorArray,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,18 @@ private static boolean isTransformedTouchPointInView(
float eventCoords[], View view) {
PointerEvents pointerEvents = view instanceof ReactPointerEventsView ?
((ReactPointerEventsView) view).getPointerEvents() : PointerEvents.AUTO;

// Views that are disabled should never be the target of pointer events. However, their children
// can be because some views (SwipeRefreshLayout) use enabled but still have children that can
// be valid targets.
if (!view.isEnabled()) {
if (pointerEvents == PointerEvents.AUTO) {
pointerEvents = PointerEvents.BOX_NONE;
} else if (pointerEvents == PointerEvents.BOX_ONLY) {
pointerEvents = PointerEvents.NONE;
}
}

if (pointerEvents == PointerEvents.NONE) {
// This view and its children can't be the target
return null;
Expand All @@ -209,7 +221,7 @@ private static boolean isTransformedTouchPointInView(
return view;

} else if (pointerEvents == PointerEvents.BOX_NONE) {
// This view can't be the target, but its children might
// This view can't be the target, but its children might.
if (view instanceof ViewGroup) {
View targetView = findTouchTargetView(eventCoords, (ViewGroup) view);
if (targetView != view) {
Expand Down

3 comments on commit 552c601

@chirag04
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@janicduplessis this only works for android right?

@janicduplessis
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chirag04 It works on both, it's just that android required a few additional changes to work.

@chirag04
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting. I did try with this commit and could not get it to work on ios. I will try a repo soon.

Please sign in to comment.