From 70e04555226fe3a57eddfb7d601ad9ff600e2b40 Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Tue, 20 Jun 2017 18:56:26 -0700 Subject: [PATCH] Implement nativeID prop to allow native code to reference react managed views in iOS Reviewed By: javache Differential Revision: D5228055 fbshipit-source-id: 8c934501d4ac946d80bf93d2ddb50f5fc38aea3c --- Libraries/Components/View/ViewPropTypes.js | 2 -- Libraries/Text/Text.js | 1 - React/Modules/RCTUIManager.h | 10 ++++++++ React/Modules/RCTUIManager.m | 27 ++++++++++++++++++++++ React/Views/RCTViewManager.m | 2 ++ React/Views/UIView+React.h | 5 ++++ React/Views/UIView+React.m | 10 ++++++++ 7 files changed, 54 insertions(+), 3 deletions(-) diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 10474a9147d..ef15ab5529c 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -218,8 +218,6 @@ module.exports = { * Used to locate this view from native classes. * * > This disables the 'layout-only view removal' optimization for this view! - * - * @platform android */ nativeID: PropTypes.string, diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index dac73a1f27c..bc9f622de13 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -179,7 +179,6 @@ const Text = React.createClass({ testID: PropTypes.string, /** * Used to locate this view from native code. - * @platform android */ nativeID: PropTypes.string, /** diff --git a/React/Modules/RCTUIManager.h b/React/Modules/RCTUIManager.h index b94b2db03b4..2c9e5057b99 100644 --- a/React/Modules/RCTUIManager.h +++ b/React/Modules/RCTUIManager.h @@ -147,6 +147,16 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey; */ - (void)rootViewForReactTag:(NSNumber *)reactTag withCompletion:(void (^)(UIView *view))completion; +/** + * Finds a view that is tagged with {@param nativeId} as its nativeID prop + * with the associated {@param rootTag} root tag view hierarchy. Returns the + * view if found, nil otherwise. + * + * @param nativeID the id reference to native component relative to root view. + * @param rootTag the react tag of root view hierarchy from which to find the view. + */ +- (UIView *)viewForNativeID:(NSString *)nativeID withRootTag:(NSNumber *)rootTag; + /** * The view that is currently first responder, according to the JS context. */ diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 57f2f0e2bac..5d5c36a4038 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -433,6 +433,33 @@ BOOL RCTIsUIManagerQueue() }); } +/** + * TODO(yuwang): implement the nativeID functionality in a more efficient way + * instead of searching the whole view tree + */ +- (UIView *)viewForNativeID:(NSString *)nativeID withRootTag:(NSNumber *)rootTag +{ + RCTAssertMainQueue(); + UIView *view = [self viewForReactTag:rootTag]; + return [self _lookupViewForNativeID:nativeID inView:view]; +} + +- (UIView *)_lookupViewForNativeID:(NSString *)nativeID inView:(UIView *)view +{ + RCTAssertMainQueue(); + if (view != nil && [nativeID isEqualToString:view.nativeID]) { + return view; + } + + for (UIView *subview in view.subviews) { + UIView *targetView = [self _lookupViewForNativeID:nativeID inView:subview]; + if (targetView != nil) { + return targetView; + } + } + return nil; +} + - (void)setSize:(CGSize)size forView:(UIView *)view { RCTAssertMainQueue(); diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index b3f259fee9b..aa305671d59 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -114,6 +114,8 @@ RCT_EXPORT_VIEW_PROPERTY(hasTVPreferredFocus, BOOL) RCT_EXPORT_VIEW_PROPERTY(tvParallaxProperties, NSDictionary) #endif +RCT_EXPORT_VIEW_PROPERTY(nativeID, NSString) + // Acessibility related properties RCT_REMAP_VIEW_PROPERTY(accessible, reactAccessibilityElement.isAccessibilityElement, BOOL) RCT_REMAP_VIEW_PROPERTY(accessibilityLabel, reactAccessibilityElement.accessibilityLabel, NSString) diff --git a/React/Views/UIView+React.h b/React/Views/UIView+React.h index e9103d01669..b81b8f645ac 100644 --- a/React/Views/UIView+React.h +++ b/React/Views/UIView+React.h @@ -24,6 +24,11 @@ - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex NS_REQUIRES_SUPER; - (void)removeReactSubview:(UIView *)subview NS_REQUIRES_SUPER; +/** + * The native id of the view, used to locate view from native codes + */ +@property (nonatomic, copy) NSString *nativeID; + /** * Layout direction of the view. * Internally backed to `semanticContentAttribute` property. diff --git a/React/Views/UIView+React.m b/React/Views/UIView+React.m index 0f6707077e0..b8970ab083a 100644 --- a/React/Views/UIView+React.m +++ b/React/Views/UIView+React.m @@ -27,6 +27,16 @@ objc_setAssociatedObject(self, @selector(reactTag), reactTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +- (NSNumber *)nativeID +{ + return objc_getAssociatedObject(self, _cmd); +} + +- (void)setNativeID:(NSNumber *)nativeID +{ + objc_setAssociatedObject(self, @selector(nativeID), nativeID, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + #if RCT_DEV - (RCTShadowView *)_DEBUG_reactShadowView