mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: Changelog: [Internal] Introducing InputAccessoryView. There is one big difference between Fabric's implementation and Paper's implementation. Fabric searches for text input from InputAccessoryView, unlike Paper where it is the other way around. Reviewed By: shergin Differential Revision: D22160445 fbshipit-source-id: 55313fe50afeced7aead5b57137d711dd1cfd3ae
154 lines
4.6 KiB
Plaintext
154 lines
4.6 KiB
Plaintext
/*
|
|
* 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 "RCTInputAccessoryComponentView.h"
|
|
|
|
#import <React/RCTBackedTextInputViewProtocol.h>
|
|
#import <React/RCTConversions.h>
|
|
#import <React/RCTSurfaceTouchHandler.h>
|
|
#import <React/UIView+React.h>
|
|
#import <react/components/inputaccessory/InputAccessoryComponentDescriptor.h>
|
|
#import <react/components/rncore/Props.h>
|
|
#import "RCTInputAccessoryContentView.h"
|
|
|
|
#import "RCTFabricComponentsPlugins.h"
|
|
|
|
using namespace facebook::react;
|
|
|
|
static UIView<RCTBackedTextInputViewProtocol> *_Nullable RCTFindTextInputWithNativeId(UIView *view, NSString *nativeId)
|
|
{
|
|
if ([view respondsToSelector:@selector(inputAccessoryViewID)] &&
|
|
[view respondsToSelector:@selector(setInputAccessoryView:)]) {
|
|
UIView<RCTBackedTextInputViewProtocol> *typed = (UIView<RCTBackedTextInputViewProtocol> *)view;
|
|
if (!nativeId || [typed.inputAccessoryViewID isEqualToString:nativeId]) {
|
|
return typed;
|
|
}
|
|
}
|
|
|
|
for (UIView *subview in view.subviews) {
|
|
UIView<RCTBackedTextInputViewProtocol> *result = RCTFindTextInputWithNativeId(subview, nativeId);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
@implementation RCTInputAccessoryComponentView {
|
|
InputAccessoryShadowNode::ConcreteState::Shared _state;
|
|
RCTInputAccessoryContentView *_contentView;
|
|
RCTSurfaceTouchHandler *_touchHandler;
|
|
UIView<RCTBackedTextInputViewProtocol> __weak *_textInput;
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
if (self = [super initWithFrame:frame]) {
|
|
static const auto defaultProps = std::make_shared<const InputAccessoryProps>();
|
|
_props = defaultProps;
|
|
_contentView = [RCTInputAccessoryContentView new];
|
|
_touchHandler = [RCTSurfaceTouchHandler new];
|
|
[_touchHandler attachToView:_contentView];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)didMoveToWindow
|
|
{
|
|
[super didMoveToWindow];
|
|
|
|
if (self.window && !_textInput) {
|
|
if (self.nativeId) {
|
|
_textInput = RCTFindTextInputWithNativeId(self.window, self.nativeId);
|
|
_textInput.inputAccessoryView = _contentView;
|
|
} else {
|
|
_textInput = RCTFindTextInputWithNativeId(_contentView, nil);
|
|
}
|
|
|
|
if (!self.nativeId) {
|
|
[self becomeFirstResponder];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)canBecomeFirstResponder
|
|
{
|
|
return true;
|
|
}
|
|
|
|
- (UIView *)inputAccessoryView
|
|
{
|
|
return _contentView;
|
|
}
|
|
|
|
#pragma mark - RCTComponentViewProtocol
|
|
|
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
{
|
|
return concreteComponentDescriptorProvider<InputAccessoryComponentDescriptor>();
|
|
}
|
|
|
|
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
{
|
|
[_contentView insertSubview:childComponentView atIndex:index];
|
|
}
|
|
|
|
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
{
|
|
[childComponentView removeFromSuperview];
|
|
}
|
|
|
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
{
|
|
auto const &oldInputAccessoryProps = *std::static_pointer_cast<InputAccessoryProps const>(_props);
|
|
auto const &newInputAccessoryProps = *std::static_pointer_cast<InputAccessoryProps const>(props);
|
|
|
|
if (newInputAccessoryProps.backgroundColor != oldInputAccessoryProps.backgroundColor) {
|
|
_contentView.backgroundColor = RCTUIColorFromSharedColor(newInputAccessoryProps.backgroundColor);
|
|
}
|
|
|
|
[super updateProps:props oldProps:oldProps];
|
|
self.hidden = true;
|
|
}
|
|
|
|
- (void)updateState:(const facebook::react::State::Shared &)state
|
|
oldState:(const facebook::react::State::Shared &)oldState
|
|
{
|
|
_state = std::static_pointer_cast<InputAccessoryShadowNode::ConcreteState const>(state);
|
|
CGSize oldScreenSize = RCTCGSizeFromSize(_state->getData().screenSize);
|
|
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
|
|
screenSize.height = std::nan("");
|
|
if (oldScreenSize.width != screenSize.width) {
|
|
auto stateData = InputAccessoryState{RCTSizeFromCGSize(screenSize)};
|
|
_state->updateState(std::move(stateData));
|
|
}
|
|
}
|
|
|
|
- (void)updateLayoutMetrics:(const facebook::react::LayoutMetrics &)layoutMetrics
|
|
oldLayoutMetrics:(const facebook::react::LayoutMetrics &)oldLayoutMetrics
|
|
{
|
|
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
|
|
|
|
[_contentView setFrame:RCTCGRectFromRect(layoutMetrics.getContentFrame())];
|
|
}
|
|
|
|
- (void)prepareForRecycle
|
|
{
|
|
[super prepareForRecycle];
|
|
_state.reset();
|
|
_textInput = nil;
|
|
}
|
|
|
|
@end
|
|
|
|
Class<RCTComponentViewProtocol> RCTInputAccessoryCls(void)
|
|
{
|
|
return RCTInputAccessoryComponentView.class;
|
|
}
|