mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
6adba409e6
Summary: This implement the autoFocus functionality natively instead of calling the focus method from JS on mount. This is needed to properly fix the issue described in https://github.com/facebook/react-native/issues/27217, where when using native navigation (UINavigationController) text input focus needs to happen in the same frame transition starts or it leads to an animation bug in UIKit. My previous attempt fixed the problem only partially and the bug could still happen since there is no guaranty code executed in useEffect will end up in the same frame as the native view being created and attached. To fix this I added an autoFocus prop to the native component on iOS and in didAttachToWindow we focus the input if it is set. This makes sure the focus is set in the same frame as the view hierarchy containing the input is created. ## Changelog [iOS] [Fixed] - Add native support for TextInput autoFocus on iOS Pull Request resolved: https://github.com/facebook/react-native/pull/27803 Test Plan: - Tested that the UI glitch when transitionning to a screen with an input with autofocus no longer happens in my app. - Tested that autofocus still works in RNTester - Made sure that onFocus does get called and TextInputState is updated properly Differential Revision: D19673369 Pulled By: TheSavior fbshipit-source-id: 14d8486ac635901622ca667c0e61c75fb446e493
148 lines
5.7 KiB
Objective-C
148 lines
5.7 KiB
Objective-C
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import <React/RCTBaseTextInputViewManager.h>
|
|
|
|
#import <React/RCTBridge.h>
|
|
#import <React/RCTConvert.h>
|
|
#import <React/RCTFont.h>
|
|
#import <React/RCTShadowView+Layout.h>
|
|
#import <React/RCTShadowView.h>
|
|
#import <React/RCTUIManager.h>
|
|
#import <React/RCTUIManagerUtils.h>
|
|
#import <React/RCTUIManagerObserverCoordinator.h>
|
|
|
|
#import <React/RCTBaseTextInputShadowView.h>
|
|
#import <React/RCTBaseTextInputView.h>
|
|
#import <React/RCTConvert+Text.h>
|
|
|
|
@interface RCTBaseTextInputViewManager () <RCTUIManagerObserver>
|
|
|
|
@end
|
|
|
|
@implementation RCTBaseTextInputViewManager
|
|
{
|
|
NSHashTable<RCTBaseTextInputShadowView *> *_shadowViews;
|
|
}
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
#pragma mark - Unified <TextInput> properties
|
|
|
|
RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType)
|
|
RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType)
|
|
RCT_REMAP_VIEW_PROPERTY(contextMenuHidden, backedTextInputView.contextMenuHidden, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance)
|
|
RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString)
|
|
RCT_REMAP_VIEW_PROPERTY(placeholderTextColor, backedTextInputView.placeholderColor, UIColor)
|
|
RCT_REMAP_VIEW_PROPERTY(returnKeyType, backedTextInputView.returnKeyType, UIReturnKeyType)
|
|
RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, UIColor)
|
|
RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType)
|
|
RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode)
|
|
RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL)
|
|
RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType)
|
|
RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
|
|
RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
|
|
RCT_EXPORT_VIEW_PROPERTY(selection, RCTTextSelection)
|
|
RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewID, NSString)
|
|
RCT_EXPORT_VIEW_PROPERTY(textContentType, NSString)
|
|
RCT_EXPORT_VIEW_PROPERTY(passwordRules, NSString)
|
|
|
|
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onTextInput, RCTDirectEventBlock)
|
|
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
|
|
|
|
RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger)
|
|
|
|
RCT_EXPORT_SHADOW_PROPERTY(text, NSString)
|
|
RCT_EXPORT_SHADOW_PROPERTY(placeholder, NSString)
|
|
RCT_EXPORT_SHADOW_PROPERTY(onContentSizeChange, RCTBubblingEventBlock)
|
|
|
|
RCT_CUSTOM_VIEW_PROPERTY(multiline, BOOL, UIView)
|
|
{
|
|
// No op.
|
|
// This View Manager doesn't use this prop but it must be exposed here via ViewConfig to enable Fabric component use it.
|
|
}
|
|
|
|
- (RCTShadowView *)shadowView
|
|
{
|
|
RCTBaseTextInputShadowView *shadowView = [[RCTBaseTextInputShadowView alloc] initWithBridge:self.bridge];
|
|
shadowView.textAttributes.fontSizeMultiplier = [[[self.bridge
|
|
moduleForName:@"AccessibilityManager"
|
|
lazilyLoadIfNecessary:YES] valueForKey:@"multiplier"] floatValue];
|
|
[_shadowViews addObject:shadowView];
|
|
return shadowView;
|
|
}
|
|
|
|
- (void)setBridge:(RCTBridge *)bridge
|
|
{
|
|
[super setBridge:bridge];
|
|
|
|
_shadowViews = [NSHashTable weakObjectsHashTable];
|
|
|
|
[bridge.uiManager.observerCoordinator addObserver:self];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(handleDidUpdateMultiplierNotification)
|
|
name:@"RCTAccessibilityManagerDidUpdateMultiplierNotification"
|
|
object:[bridge moduleForName:@"AccessibilityManager"
|
|
lazilyLoadIfNecessary:YES]];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(focus : (nonnull NSNumber *)viewTag)
|
|
{
|
|
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
UIView *view = viewRegistry[viewTag];
|
|
[view reactFocus];
|
|
}];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(blur : (nonnull NSNumber *)viewTag)
|
|
{
|
|
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
UIView *view = viewRegistry[viewTag];
|
|
[view reactBlur];
|
|
}];
|
|
}
|
|
|
|
#pragma mark - RCTUIManagerObserver
|
|
|
|
- (void)uiManagerWillPerformMounting:(__unused RCTUIManager *)uiManager
|
|
{
|
|
for (RCTBaseTextInputShadowView *shadowView in _shadowViews) {
|
|
[shadowView uiManagerWillPerformMounting];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Font Size Multiplier
|
|
|
|
- (void)handleDidUpdateMultiplierNotification
|
|
{
|
|
CGFloat fontSizeMultiplier = [[[self.bridge moduleForName:@"AccessibilityManager"]
|
|
valueForKey:@"multiplier"] floatValue];
|
|
|
|
NSHashTable<RCTBaseTextInputShadowView *> *shadowViews = _shadowViews;
|
|
RCTExecuteOnUIManagerQueue(^{
|
|
for (RCTBaseTextInputShadowView *shadowView in shadowViews) {
|
|
shadowView.textAttributes.fontSizeMultiplier = fontSizeMultiplier;
|
|
[shadowView dirtyLayout];
|
|
}
|
|
|
|
[self.bridge.uiManager setNeedsLayout];
|
|
});
|
|
}
|
|
|
|
@end
|