[ReactNative] Element Inspector

Summary:
This adds new development feature to React Native that provides information
about selected element (see the demo in Test Plan).

This is how it works:

App's root component is rendered to a container that also has a hidden layer called
`<InspectorOverlay/>`. When activated, it shows full screen view and captures all
touches. On every touch we ask UIManager to find a view for given {x,y} coordinates.

Then, we use React's internals to find corresponding React component. `setRootInstance`
is used to remember the top level component to start search from, lmk if you have a
better idea how to do this. Given a component, we can climb up its owners tree
to provice more context on how/where the component is used.

In future we could use the `hierarchy` array to inspect and print their props/state.

Known bugs and limitations:
* InspectorOverlay sometimes receives touches with incorrect coordinates (wtf)
* Not integrated with React Chrome Devtools (maybe in followup diffs)
* Doesn't work with popovers (maybe put the element inspector into an `<Overlay/>`?)

@public

Test Plan:
https://www.facebook.com/pxlcld/mn5k
Works nicely with scrollviews
This commit is contained in:
Alex Kotliarskyi
2015-05-26 11:16:25 -07:00
parent 4273af9e29
commit cfa4b13472
5 changed files with 252 additions and 7 deletions

View File

@@ -882,6 +882,31 @@ RCT_EXPORT_METHOD(blur:(NSNumber *)reactTag)
}];
}
RCT_EXPORT_METHOD(findSubviewIn:(NSNumber *)reactTag atPoint:(CGPoint)point callback:(RCTResponseSenderBlock)callback) {
if (!reactTag) {
callback(@[[NSNull null]]);
return;
}
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
UIView *view = viewRegistry[reactTag];
UIView *target = [view hitTest:point withEvent:nil];
CGRect frame = [target convertRect:target.bounds toView:view];
while (target.reactTag == nil && target.superview != nil) {
target = [target superview];
}
callback(@[
target.reactTag ?: [NSNull null],
@(frame.origin.x),
@(frame.origin.y),
@(frame.size.width),
@(frame.size.height),
]);
}];
}
- (void)batchDidComplete
{
// Gather blocks to be executed now that all view hierarchy manipulations have