Add support for needsOffscreenAlphaCompositing on iOS (#19052)

Summary:
Currently on iOS in UIKit and in RN all views are by default set to `allowsGroupOpacity=true`. Any view that has all of the following
- `allowsGroupOpacity` set to true
- opacity greater than 0.0 and less than 1.0
- have any subviews

will be rendered off screen (on CPU). [See this link for more details](https://stackoverflow.com/questions/13158796/what-triggers-offscreen-rendering-blending-and-layoutsubviews-in-ios/13649143#13649143).  Which means performance will be decreased and may affect the user experience. Therefore it makes sense to allow the developers to override this property.

This pull request allows for changing `allowsGroupOpacity` via `needsOffscreenAlphaCompositing`. Android already supports this. This is not a new name or variable. See https://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing.
Pull Request resolved: https://github.com/facebook/react-native/pull/19052

Differential Revision: D14071300

Pulled By: hramos

fbshipit-source-id: 004278801a19463ebf9da6f8855f02ed27926025
This commit is contained in:
Håvard Fossli
2019-02-13 16:24:41 -08:00
committed by Facebook Github Bot
parent 9101ebdfbb
commit cf5f25472d
3 changed files with 115 additions and 0 deletions

View File

@@ -124,6 +124,33 @@ RCT_CUSTOM_VIEW_PROPERTY(customProp, NSString, RCTPropsTestView)
RCT_RUN_RUNLOOP_WHILE(view == nil);
}
- (void)testNeedsOffscreenAlphaCompositing
{
__block RCTPropsTestView *view;
RCTUIManager *uiManager = _bridge.uiManager;
XCTestExpectation *initialExpectation = [self expectationWithDescription:@"initial expectation"];
XCTestExpectation *updateExpectation = [self expectationWithDescription:@"second expectation"];
dispatch_async(uiManager.methodQueue, ^{
[uiManager createView:@2 viewName:@"RCTPropsTestView" rootTag:self->_rootViewReactTag props:@{}];
[uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
view = (RCTPropsTestView *)viewRegistry[@2];
XCTAssertEqual(view.layer.allowsGroupOpacity, TRUE);
[initialExpectation fulfill];
}];
[uiManager updateView:@2 viewName:@"RCTPropsTestView" props:@{@"needsOffscreenAlphaCompositing": @NO}];
[uiManager addUIBlock:^(__unused RCTUIManager *_uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
view = (RCTPropsTestView *)viewRegistry[@2];
XCTAssertEqual(view.layer.allowsGroupOpacity, FALSE);
[updateExpectation fulfill];
}];
[uiManager setNeedsLayout];
});
[self waitForExpectations:@[initialExpectation, updateExpectation] timeout:0.1];
}
- (void)testResetProps
{
__block RCTPropsTestView *view;

View File

@@ -225,6 +225,93 @@ exports.examples = [
);
},
},
{
title: 'Offscreen Alpha Compositing',
render() {
type Props = $ReadOnly<{||}>;
type State = {|
active: boolean,
|};
const styles = StyleSheet.create({
alphaCompositing: {
justifyContent: 'space-around',
width: 100,
height: 50,
borderRadius: 100,
},
});
class OffscreenAlphaCompositing extends React.Component<Props, State> {
state = {
active: false,
};
render() {
return (
<TouchableWithoutFeedback onPress={this._handlePress}>
<View>
<Text style={{paddingBottom: 10}}>Blobs</Text>
<View
style={{opacity: 1.0, paddingBottom: 30}}
needsOffscreenAlphaCompositing={this.state.active}>
<View
style={[
styles.alphaCompositing,
{marginTop: 0, marginLeft: 0, backgroundColor: '#FF6F59'},
]}
/>
<View
style={[
styles.alphaCompositing,
{
marginTop: -50,
marginLeft: 50,
backgroundColor: '#F7CB15',
},
]}
/>
</View>
<Text style={{paddingBottom: 10}}>
Same blobs, but their shared container have 0.5 opacity
</Text>
<Text style={{paddingBottom: 10}}>
Tap to {this.state.active ? 'activate' : 'deactivate'}{' '}
needsOffscreenAlphaCompositing
</Text>
<View
style={{opacity: 0.8}}
needsOffscreenAlphaCompositing={this.state.active}>
<View
style={[
styles.alphaCompositing,
{marginTop: 0, marginLeft: 0, backgroundColor: '#FF6F59'},
]}
/>
<View
style={[
styles.alphaCompositing,
{
marginTop: -50,
marginLeft: 50,
backgroundColor: '#F7CB15',
},
]}
/>
</View>
</View>
</TouchableWithoutFeedback>
);
}
_handlePress = () => {
this.setState({active: !this.state.active});
};
}
return <OffscreenAlphaCompositing />;
},
},
{
title: 'ZIndex',
render() {

View File

@@ -129,6 +129,7 @@ RCT_REMAP_VIEW_PROPERTY(shadowColor, layer.shadowColor, CGColor)
RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize)
RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, float)
RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat)
RCT_REMAP_VIEW_PROPERTY(needsOffscreenAlphaCompositing, layer.allowsGroupOpacity, BOOL)
RCT_CUSTOM_VIEW_PROPERTY(overflow, YGOverflow, RCTView)
{
if (json) {