From f67fa82008918e9e2875387db658911d197a6956 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Tue, 1 Mar 2016 06:50:33 -0800 Subject: [PATCH] Add UIManager.measureInWindow to get window coordinates Summary: When embedding in a hybrid app, we sometimes present new modal views or windows that have a different frame from the original root view. This API allows us to get coordinates in the application's window frame, which should be valid in any fullscreen view. Reviewed By: majak Differential Revision: D2939827 fb-gh-sync-id: 06b93cc2cb3519a25819c6efa445c779314dd673 shipit-source-id: 06b93cc2cb3519a25819c6efa445c779314dd673 --- Libraries/ReactIOS/NativeMethodsMixin.js | 29 ++++++++++++++++++++++++ React/Modules/RCTUIManager.m | 23 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/Libraries/ReactIOS/NativeMethodsMixin.js b/Libraries/ReactIOS/NativeMethodsMixin.js index c288ea8a01b03c..f70a2821165ebd 100644 --- a/Libraries/ReactIOS/NativeMethodsMixin.js +++ b/Libraries/ReactIOS/NativeMethodsMixin.js @@ -27,6 +27,13 @@ type MeasureOnSuccessCallback = ( pageY: number ) => void +type MeasureInWindowOnSuccessCallback = ( + x: number, + y: number, + width: number, + height: number, +) => void + type MeasureLayoutOnSuccessCallback = ( left: number, top: number, @@ -83,6 +90,28 @@ var NativeMethodsMixin = { ); }, + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow: function(callback: MeasureInWindowOnSuccessCallback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + /** * Like [`measure()`](#measure), but measures the view relative an ancestor, * specified as `relativeToNativeNode`. This means that the returned x, y diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index fdce4858327674..d71939130f3246 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1076,6 +1076,29 @@ - (void)setNeedsLayout }]; } +RCT_EXPORT_METHOD(measureInWindow:(nonnull NSNumber *)reactTag + callback:(RCTResponseSenderBlock)callback) +{ + [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { + UIView *view = viewRegistry[reactTag]; + if (!view) { + // this view was probably collapsed out + RCTLogWarn(@"measure cannot find view with tag #%@", reactTag); + callback(@[]); + return; + } + + // Return frame coordinates in window + CGRect windowFrame = [view.window convertRect:view.frame fromView:view.superview]; + callback(@[ + @(windowFrame.origin.x), + @(windowFrame.origin.y), + @(windowFrame.size.width), + @(windowFrame.size.height), + ]); + }]; +} + static void RCTMeasureLayout(RCTShadowView *view, RCTShadowView *ancestor, RCTResponseSenderBlock callback)