Add backface-visibility support on Android (#15970)

Summary:
`backfaceVisibility` was only available on iOS and 3D transformations were lacking on Android.

Backface Visibility is computed from ~the decomposed matrix of transform prop~ the view with their rotation degree values.

~`MatrixDecompositionContext` properties have been made public so we can access to decomposed matrix values from outside (`ReactViewGroup`).~

I'm not sure if this is the best implementation, so if it's not let's discuss it.

cc janicduplessis foghina

Tested in https://github.com/charpeni/react-native-backface-visibility.

| Before | Now |
| - | - |
| <img src="https://user-images.githubusercontent.com/7189823/30123717-e5361598-9300-11e7-8e2e-a87a7a8d896a.gif" width="260" /> | <img src="https://user-images.githubusercontent.com/7189823/30514997-4d203572-9aee-11e7-8542-bfde41678eb6.gif" width="244" /> |

| iOS | Android |
| - | - |
| <img src="https://user-images.githubusercontent.com/7189823/36995899-609513b4-2083-11e8-9834-ee44c1a292e1.gif" width="300" /> | <img src="https://user-images.githubusercontent.com/7189823/36995978-9ed3b158-2083-11e8-841e-b9e3357d2509.gif" width="240" /> |

[ANDROID] [FEATURE] [ReactViewGroup] - Add backface-visibility support on Android
Pull Request resolved: https://github.com/facebook/react-native/pull/15970

Differential Revision: D9411130

Pulled By: hramos

fbshipit-source-id: 62f646a4de37d83922286cb98893a95b55fa889e
This commit is contained in:
Nicolas Charpentier 2018-09-06 15:35:50 -07:00 committed by Facebook Github Bot
parent 2f79960a69
commit 0cce0a62c1
6 changed files with 118 additions and 0 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 200 KiB

View File

@ -311,4 +311,72 @@ exports.examples = [
return <ZIndexExample />; return <ZIndexExample />;
}, },
}, },
{
title: 'BackfaceVisibility',
render: function() {
return (
<>
<Text style={{paddingBottom: 10}}>
View #1, front is visible, back is hidden.
</Text>
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<View
style={{
height: 200,
width: 200,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'blue',
backfaceVisibility: 'hidden',
}}>
<Text>Front</Text>
</View>
<View
style={{
height: 200,
width: 200,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red',
backfaceVisibility: 'hidden',
transform: [{rotateY: '180deg'}],
position: 'absolute',
top: 0,
}}>
<Text>Back (You should not see this)</Text>
</View>
</View>
<Text style={{paddingVertical: 10}}>
View #2, front is hidden, back is visible.
</Text>
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<View
style={{
height: 200,
width: 200,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'blue',
backfaceVisibility: 'hidden',
}}>
<Text>Front (You should not see this)</Text>
</View>
<View
style={{
height: 200,
width: 200,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red',
backfaceVisibility: 'hidden',
position: 'absolute',
top: 0,
}}>
<Text>Back</Text>
</View>
</View>
</>
);
},
},
]; ];

View File

@ -110,6 +110,8 @@ public class ReactViewGroup extends ViewGroup implements
private final ViewGroupDrawingOrderHelper mDrawingOrderHelper; private final ViewGroupDrawingOrderHelper mDrawingOrderHelper;
private @Nullable Path mPath; private @Nullable Path mPath;
private int mLayoutDirection; private int mLayoutDirection;
private float mBackfaceOpacity = 1.f;
private String mBackfaceVisibility = "visible";
public ReactViewGroup(Context context) { public ReactViewGroup(Context context) {
super(context); super(context);
@ -836,4 +838,36 @@ public class ReactViewGroup extends ViewGroup implements
} }
} }
} }
public void setOpacityIfPossible(float opacity) {
mBackfaceOpacity = opacity;
setBackfaceVisibilityDependantOpacity();
}
public void setBackfaceVisibility(String backfaceVisibility) {
mBackfaceVisibility = backfaceVisibility;
setBackfaceVisibilityDependantOpacity();
}
public void setBackfaceVisibilityDependantOpacity() {
boolean isBackfaceVisible = mBackfaceVisibility.equals("visible");
if (isBackfaceVisible) {
setAlpha(mBackfaceOpacity);
return;
}
float rotationX = getRotationX();
float rotationY = getRotationY();
boolean isFrontfaceVisible = (rotationX >= -90.f && rotationX < 90.f) &&
(rotationY >= -90.f && rotationY < 90.f);
if (isFrontfaceVisible) {
setAlpha(mBackfaceOpacity);
return;
}
setAlpha(0);
}
} }

View File

@ -203,6 +203,22 @@ public class ReactViewManager extends ViewGroupManager<ReactViewGroup> {
view.setOverflow(overflow); view.setOverflow(overflow);
} }
@ReactProp(name = "backfaceVisibility")
public void setBackfaceVisibility(ReactViewGroup view, String backfaceVisibility) {
view.setBackfaceVisibility(backfaceVisibility);
}
@Override
public void setOpacity(ReactViewGroup view, float opacity) {
view.setOpacityIfPossible(opacity);
}
@Override
public void setTransform(ReactViewGroup view, ReadableArray matrix) {
super.setTransform(view, matrix);
view.setBackfaceVisibilityDependantOpacity();
}
@Override @Override
public String getName() { public String getName() {
return REACT_CLASS; return REACT_CLASS;