Files
react-native/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm
T
Samuel Susla c907202d2b Fix touch handling in bridged paper components
Summary:
Changelog: [internal]

If view was bridged from Paper, hit testing would return Paper view which doesn't have reference to Fabric's event emitter.
To fix this, if the bridged view is returned from hit testing, it is swapped with interop view which has reference to event emitter.

Reviewed By: shergin

Differential Revision: D23840054

fbshipit-source-id: d4aa4ee8da4e1da80d2e2b69b79ed82d726f04e3
2020-09-24 01:07:23 -07:00

179 lines
5.9 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 "RCTLegacyViewManagerInteropComponentView.h"
#import <React/UIView+React.h>
#import <react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropComponentDescriptor.h>
#import <react/renderer/components/legacyviewmanagerinterop/LegacyViewManagerInteropViewProps.h>
#import <react/utils/ManagedObjectWrapper.h>
#import "RCTLegacyViewManagerInteropCoordinatorAdapter.h"
using namespace facebook::react;
static NSString *const kRCTLegacyInteropChildComponentKey = @"childComponentView";
static NSString *const kRCTLegacyInteropChildIndexKey = @"index";
@implementation RCTLegacyViewManagerInteropComponentView {
NSMutableArray<NSDictionary *> *_viewsToBeMounted;
NSMutableArray<UIView *> *_viewsToBeUnmounted;
RCTLegacyViewManagerInteropCoordinatorAdapter *_adapter;
LegacyViewManagerInteropShadowNode::ConcreteStateTeller _stateTeller;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const LegacyViewManagerInteropViewProps>();
_props = defaultProps;
_viewsToBeMounted = [NSMutableArray new];
_viewsToBeUnmounted = [NSMutableArray new];
}
return self;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *result = [super hitTest:point withEvent:event];
if (result == _adapter.paperView) {
return self;
}
return result;
}
+ (NSMutableSet<NSString *> *)supportedViewManagers
{
static NSMutableSet<NSString *> *supported = [NSMutableSet setWithObjects:@"Picker",
@"DatePicker",
@"ProgressView",
@"SegmentedControl",
@"MaskedView",
@"ARTSurfaceView",
@"ARTText",
@"ARTShape",
@"ARTGroup",
nil];
return supported;
}
+ (BOOL)isSupported:(NSString *)componentName
{
return [[RCTLegacyViewManagerInteropComponentView supportedViewManagers] containsObject:componentName];
}
+ (void)supportLegacyViewManagerWithName:(NSString *)componentName
{
[[RCTLegacyViewManagerInteropComponentView supportedViewManagers] addObject:componentName];
}
- (RCTLegacyViewManagerInteropCoordinator *)coordinator
{
auto data = _stateTeller.getData();
if (data.hasValue()) {
return unwrapManagedObject(data.value().coordinator);
} else {
return nil;
}
}
- (NSString *)componentViewName_DO_NOT_USE_THIS_IS_BROKEN
{
return self.coordinator.componentViewName;
}
#pragma mark - RCTComponentViewProtocol
- (void)prepareForRecycle
{
_adapter = nil;
[_viewsToBeMounted removeAllObjects];
[_viewsToBeUnmounted removeAllObjects];
_stateTeller.invalidate();
self.contentView = nil;
[super prepareForRecycle];
}
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
[_viewsToBeMounted addObject:@{
kRCTLegacyInteropChildIndexKey : [NSNumber numberWithInteger:index],
kRCTLegacyInteropChildComponentKey : childComponentView
}];
}
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
if (_adapter) {
[_adapter.paperView removeReactSubview:childComponentView];
} else {
[_viewsToBeUnmounted addObject:childComponentView];
}
}
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<LegacyViewManagerInteropComponentDescriptor>();
}
- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState
{
_stateTeller.setConcreteState(state);
}
- (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
{
[super finalizeUpdates:updateMask];
if (!_adapter) {
_adapter = [[RCTLegacyViewManagerInteropCoordinatorAdapter alloc] initWithCoordinator:self.coordinator
reactTag:self.tag];
__weak __typeof(self) weakSelf = self;
_adapter.eventInterceptor = ^(std::string eventName, folly::dynamic event) {
if (weakSelf) {
__typeof(self) strongSelf = weakSelf;
auto eventEmitter =
std::static_pointer_cast<LegacyViewManagerInteropViewEventEmitter const>(strongSelf->_eventEmitter);
eventEmitter->dispatchEvent(eventName, event);
}
};
self.contentView = _adapter.paperView;
}
for (NSDictionary *mountInstruction in _viewsToBeMounted) {
NSNumber *index = mountInstruction[kRCTLegacyInteropChildIndexKey];
UIView *childView = mountInstruction[kRCTLegacyInteropChildComponentKey];
[_adapter.paperView insertReactSubview:childView atIndex:index.integerValue];
}
[_viewsToBeMounted removeAllObjects];
for (UIView *view in _viewsToBeUnmounted) {
[_adapter.paperView removeReactSubview:view];
}
[_viewsToBeUnmounted removeAllObjects];
[_adapter.paperView didUpdateReactSubviews];
if (updateMask & RNComponentViewUpdateMaskProps) {
const auto &newProps = *std::static_pointer_cast<const LegacyViewManagerInteropViewProps>(_props);
[_adapter setProps:newProps.otherProps];
}
}
#pragma mark - Native Commands
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
{
[_adapter handleCommand:(NSString *)commandName args:(NSArray *)args];
}
@end