diff --git a/Libraries/ReactIOS/NativeMethodsMixin.js b/Libraries/ReactIOS/NativeMethodsMixin.js index c288ea8a01..f70a282116 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 fdce485832..d71939130f 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1076,6 +1076,29 @@ RCT_EXPORT_METHOD(measure:(nonnull NSNumber *)reactTag }]; } +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)