[ReactNative] Introduce onLayout events

Summary:
Simply add an `onLayout` callback to a native view component, and the callback
will be invoked with the current layout information when the view is mounted and
whenever the layout changes.

The only limitation is that scroll position and other stuff the layout system
isn't aware of is not taken into account.  This is because onLayout events
wouldn't be triggered for these changes and if they are desired they should be
tracked separately (e.g. with `onScroll`) and combined.

Also fixes some bugs with LayoutAnimation callbacks.

@public

Test Plan:
- Run new LayoutEventsExample in UIExplorer and see it work correctly.
- New integration test passes internally (IntegrationTest project seems busted).
- New jest test case passes.

{F22318433}

```
2015-05-06 15:45:05.848 [info][tid:com.facebook.React.JavaScript] "Running application "UIExplorerApp" with appParams: {"rootTag":1,"initialProps":{}}. __DEV__ === true, development-level warning are ON, performance optimizations are OFF"
2015-05-06 15:45:05.881 [info][tid:com.facebook.React.JavaScript] "received text layout event
", {"target":27,"layout":{"y":123,"x":12.5,"width":140.5,"height":18}}
2015-05-06 15:45:05.882 [info][tid:com.facebook.React.JavaScript] "received image layout event
", {"target":23,"layout":{"y":12.5,"x":122,"width":50,"height":50}}
2015-05-06 15:45:05.883 [info][tid:com.facebook.React.JavaScript] "received view layout event
", {"target":22,"layout":{"y":70.5,"x":20,"width":294,"height":204}}
2015-05-06 15:45:05.897 [info][tid:com.facebook.React.JavaScript] "received text layout event
", {"target":27,"layout":{"y":206.5,"x":12.5,"width":140.5,"height":18}}
2015-05-06 15:45:05.897 [info][tid:com.facebook.React.JavaScript] "received view layout event
", {"target":22,"layout":{"y":70.5,"x":20,"width":294,"height":287.5}}
2015-05-06 15:45:09.847 [info][tid:com.facebook.React.JavaScript] "layout animation done."
2015-05-06 15:45:09.847 [info][tid:com.facebook.React.JavaScript] "received image layout event
", {"target":23,"layout":{"y":12.5,"x":82,"width":50,"height":50}}
2015-05-06 15:45:09.848 [info][tid:com.facebook.React.JavaScript] "received view layout event
", {"target":22,"layout":{"y":110.5,"x":60,"width":214,"height":287.5}}
2015-05-06 15:45:09.862 [info][tid:com.facebook.React.JavaScript] "received text layout event
", {"target":27,"layout":{"y":206.5,"x":12.5,"width":120,"height":68}}
2015-05-06 15:45:09.863 [info][tid:com.facebook.React.JavaScript] "received image layout event
", {"target":23,"layout":{"y":12.5,"x":55,"width":50,"height":50}}
2015-05-06 15:45:09.863 [info][tid:com.facebook.React.JavaScript] "received view layout event
", {"target":22,"layout":{"y":128,"x":60,"width":160,"height":337.5}}
```
This commit is contained in:
Spencer Ahrens
2015-05-07 12:11:02 -07:00
parent f251b0ddb8
commit 1ef4e00fba
11 changed files with 389 additions and 11 deletions

View File

@@ -9,8 +9,7 @@
* @providesModule ReactIOSViewAttributes
* @flow
*/
"use strict";
'use strict';
var merge = require('merge');
@@ -21,6 +20,7 @@ ReactIOSViewAttributes.UIView = {
accessible: true,
accessibilityLabel: true,
testID: true,
onLayout: true,
};
ReactIOSViewAttributes.RCTView = merge(
@@ -31,7 +31,7 @@ ReactIOSViewAttributes.RCTView = merge(
// For this property to be effective, it must be applied to a view that contains
// many subviews that extend outside its bound. The subviews must also have
// overflow: hidden, as should the containing view (or one of its superviews).
removeClippedSubviews: true
removeClippedSubviews: true,
});
module.exports = ReactIOSViewAttributes;

View File

@@ -42,6 +42,16 @@ function diffRawProperties(
}
prevProp = prevProps && prevProps[propKey];
nextProp = nextProps[propKey];
// functions are converted to booleans as markers that the associated
// events should be sent from native.
if (typeof prevProp === 'function') {
prevProp = true;
}
if (typeof nextProp === 'function') {
nextProp = true;
}
if (prevProp !== nextProp) {
// If you want a property's diff to be detected, you must configure it
// to be so - *or* it must be a scalar property. For now, we'll allow
@@ -75,6 +85,16 @@ function diffRawProperties(
}
prevProp = prevProps[propKey];
nextProp = nextProps && nextProps[propKey];
// functions are converted to booleans as markers that the associated
// events should be sent from native.
if (typeof prevProp === 'function') {
prevProp = true;
}
if (typeof nextProp === 'function') {
nextProp = true;
}
if (prevProp !== nextProp) {
if (nextProp === undefined) {
nextProp = null; // null is a sentinel we explicitly send to native