Skip to content

Commit 7121c42

Browse files
Android ZOrder for transparent surfaceView (#460)
* overlay property * setZOrderMediaOverlay instead of setZOrderOnTop * Update Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineView.java Co-authored-by: Ryan Tremblay <[email protected]> * Android view property * PR feedback * Update Modules/@babylonjs/react-native/README.md Co-authored-by: Ryan Tremblay <[email protected]> * Update Modules/@babylonjs/react-native/README.md Co-authored-by: Ryan Tremblay <[email protected]> * removed commented code Co-authored-by: Ryan Tremblay <[email protected]>
1 parent 522e4a9 commit 7121c42

File tree

8 files changed

+43
-45
lines changed

8 files changed

+43
-45
lines changed

Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineView.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ public final class EngineView extends FrameLayout implements SurfaceHolder.Callb
3333

3434
private SurfaceView xrSurfaceView;
3535
private boolean isTransparent = false;
36-
private boolean isTopMost = false;
36+
private String androidView = "";
3737
private final EventDispatcher reactEventDispatcher;
3838
private Runnable renderRunnable;
3939

4040
public EngineView(ReactContext reactContext) {
4141
super(reactContext);
4242

43-
this.setIsTransparentAndIsTopMost(false, false);
43+
this.setIsTransparentAndAndroidView(false, "");
4444

4545
this.xrSurfaceView = new SurfaceView(reactContext);
4646
this.xrSurfaceView.setLayoutParams(childViewLayoutParams);
@@ -72,17 +72,18 @@ public void setAntiAliasing(Integer value) {
7272
BabylonNativeInterop.updateMSAA(value);
7373
}
7474

75-
public void setIsTopMost(Boolean isTopMost) {
76-
setIsTransparentAndIsTopMost(this.isTransparent, isTopMost);
77-
}
7875
// ------------------------------------
79-
// TextureView related
76+
77+
public void setAndroidView(String androidView) {
78+
setIsTransparentAndAndroidView(this.isTransparent, androidView);
79+
}
80+
8081
public void setIsTransparent(Boolean isTransparent) {
81-
setIsTransparentAndIsTopMost(isTransparent, this.isTopMost);
82+
setIsTransparentAndAndroidView(isTransparent, this.androidView);
8283
}
8384

84-
private void setIsTransparentAndIsTopMost(Boolean isTransparent, Boolean isTopMost) {
85-
if (this.isTransparent == isTransparent && this.isTopMost == isTopMost &&
85+
private void setIsTransparentAndAndroidView(Boolean isTransparent, String androidView) {
86+
if (this.isTransparent == isTransparent && this.androidView.equals(androidView) &&
8687
(this.surfaceView != null || this.transparentTextureView != null)) {
8788
return;
8889
}
@@ -94,30 +95,34 @@ private void setIsTransparentAndIsTopMost(Boolean isTransparent, Boolean isTopMo
9495
this.transparentTextureView.setVisibility(View.GONE);
9596
this.transparentTextureView = null;
9697
}
97-
if (isTransparent && !isTopMost) {
98+
99+
if (androidView.equals("TextureView")) {
98100
this.transparentTextureView = new TextureView(this.getContext());
99101
this.transparentTextureView.setLayoutParams(EngineView.childViewLayoutParams);
100102
this.transparentTextureView.setSurfaceTextureListener(this);
101-
this.transparentTextureView.setOpaque(false);
103+
this.transparentTextureView.setOpaque(isTransparent);
102104
this.addView(this.transparentTextureView);
103105
} else {
104106
this.surfaceView = new SurfaceView(this.getContext());
105107
this.surfaceView.setLayoutParams(EngineView.childViewLayoutParams);
106108
SurfaceHolder surfaceHolder = this.surfaceView.getHolder();
109+
107110
if (isTransparent) {
111+
// transparent and androidView equals "SurfaceView" will give an opaque SurfaceView
108112
surfaceHolder.setFormat(PixelFormat.TRANSPARENT);
109113
}
110-
if (isTopMost) {
111-
// ZOrder is not dynamic before Android 11. Recreate the surfaceView and set order before adding to the parent
112-
// https://developer.android.com/reference/android/view/SurfaceView#setZOrderOnTop(boolean)
114+
if ((androidView.equals("") && isTransparent) || androidView.equals("SurfaceViewZTopMost")) {
113115
this.surfaceView.setZOrderOnTop(true);
116+
} else if (androidView.equals("SurfaceViewZMediaOverlay")) {
117+
this.surfaceView.setZOrderMediaOverlay(true);
114118
}
119+
115120
surfaceHolder.addCallback(this);
116121
this.addView(this.surfaceView);
117122
}
118123

119124
this.isTransparent = isTransparent;
120-
this.isTopMost = isTopMost;
125+
this.androidView = androidView;
121126

122127
// xr view needs to be on top of views that might be created after it.
123128
if (this.xrSurfaceView != null) {

Modules/@babylonjs/react-native-iosandroid/android/src/main/java/com/babylonreactnative/EngineViewManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ public void setAntiAliasing(EngineView view, Integer value) {
3333
view.setAntiAliasing(value);
3434
}
3535

36-
@ReactProp(name = "isTopMost")
37-
public void setIsTopMost(EngineView view, Boolean isTopMost) {
38-
view.setIsTopMost(isTopMost);
36+
@ReactProp(name = "androidView")
37+
public void setAndroidView(EngineView view, String androidView) {
38+
view.setAndroidView(androidView);
3939
}
4040

4141
@NonNull

Modules/@babylonjs/react-native-iosandroid/ios/EngineViewManager.mm

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ @interface EngineView : MTKView
1313
@property (nonatomic, copy) RCTDirectEventBlock onSnapshotDataReturned;
1414
@property (nonatomic, assign) BOOL isTransparent;
1515
@property (nonatomic, assign) NSNumber* antiAliasing;
16-
@property (nonatomic, assign) BOOL isTopMost;
1716

1817
@end
1918

@@ -46,12 +45,6 @@ - (void)setMSAA:(NSNumber*)value {
4645
[BabylonNativeInterop updateMSAA:value];
4746
}
4847

49-
- (void)setIsTopMostFlag:(NSNumber*)isTopMostFlag {
50-
BOOL isTopMost = [isTopMostFlag intValue] == 1;
51-
self.layer.zPosition = isTopMost ? FLT_MAX : 0.f;
52-
self.isTopMost = isTopMost;
53-
}
54-
5548
- (void)setBounds:(CGRect)bounds {
5649
[super setBounds:bounds];
5750
[BabylonNativeInterop updateView:self];
@@ -133,10 +126,6 @@ @implementation EngineViewManager
133126
[view setMSAA:json];
134127
}
135128

136-
RCT_CUSTOM_VIEW_PROPERTY(isTopMost, NSNumber*, EngineView){
137-
[view setIsTopMostFlag:json];
138-
}
139-
140129
RCT_EXPORT_MODULE(EngineViewManager)
141130

142131
RCT_EXPORT_VIEW_PROPERTY(onSnapshotDataReturned, RCTDirectEventBlock)

Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineView.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,6 @@ namespace winrt::BabylonReactNative::implementation {
188188
{
189189
auto value = propertyValue.AsUInt8();
190190
BabylonNative::UpdateMSAA(value);
191-
} else if (propertyName == "isTopMost")
192-
{
193-
// todo: implementation
194191
}
195192
}
196193
}

Modules/@babylonjs/react-native-windows/windows/BabylonReactNative/EngineViewManager.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ namespace winrt::BabylonReactNative::implementation {
3838

3939
nativeProps.Insert(L"isTransparent", ViewManagerPropertyType::Boolean);
4040
nativeProps.Insert(L"antiAliasing", ViewManagerPropertyType::Number);
41-
nativeProps.Insert(L"isTopMost", ViewManagerPropertyType::Boolean);
4241

4342
return nativeProps.GetView();
4443
}

Modules/@babylonjs/react-native/EngineView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export interface EngineViewProps extends ViewProps {
99
camera?: Camera;
1010
displayFrameRate?: boolean;
1111
isTransparent?: boolean;
12-
isTopMost?: boolean;
12+
androidView?: "TextureView" | "SurfaceView" | "SurfaceViewZTopMost" | "SurfaceViewZMediaOverlay";
1313
antiAliasing?: 0 | 1 | 2 | 4 | 8 | 16;
1414
onInitialized?: (view: EngineViewCallbacks) => void;
1515
}
@@ -30,7 +30,7 @@ export const EngineView: FunctionComponent<EngineViewProps> = (props: EngineView
3030
const snapshotPromise = useRef<{ promise: Promise<string>, resolve: (data: string) => void }>();
3131
const isTransparent = props.isTransparent ?? false;
3232
const antiAliasing = props.antiAliasing ?? 0;
33-
const isTopMost = props.isTopMost ?? false;
33+
const androidView = props.androidView ?? "";
3434

3535
const initialized = useModuleInitializer();
3636

@@ -116,7 +116,7 @@ export const EngineView: FunctionComponent<EngineViewProps> = (props: EngineView
116116
if (initialized !== false) {
117117
return (
118118
<View style={[{ flex: 1 }, props.style, { overflow: "hidden" }]}>
119-
{ initialized && <NativeEngineView ref={engineViewRef} style={{ flex: 1 }} onSnapshotDataReturned={snapshotDataReturnedHandler} isTransparent={isTransparent} antiAliasing={antiAliasing} isTopMost={isTopMost}/> }
119+
{ initialized && <NativeEngineView ref={engineViewRef} style={{ flex: 1 }} onSnapshotDataReturned={snapshotDataReturnedHandler} isTransparent={isTransparent} antiAliasing={antiAliasing} androidView={androidView}/> }
120120
{ sceneStats !== undefined &&
121121
<View style={{ backgroundColor: '#00000040', opacity: 1, position: 'absolute', right: 0, left: 0, top: 0, flexDirection: 'row-reverse' }}>
122122
<Text style={{ color: 'yellow', alignSelf: 'flex-end', margin: 3, fontVariant: ['tabular-nums'] }}>FPS: {sceneStats.frameRate.toFixed(0)}</Text>

Modules/@babylonjs/react-native/NativeEngineView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ declare const global: any;
66
export interface NativeEngineViewProps extends ViewProps {
77
isTransparent: boolean;
88
antiAliasing: number;
9-
isTopMost: boolean;
9+
androidView: string;
1010
onSnapshotDataReturned?: (event: SyntheticEvent) => void;
1111
}
1212

Modules/@babylonjs/react-native/README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,6 @@ e.g.
8989
```tsx
9090
<EngineView style={{flex: 1}} camera={camera} isTransparent={true} />
9191
```
92-
`isTopMost` is a flag that allows to place the view on top of any other view. When enabled, this allows a huge performance improvement on Android with Transparency on.
93-
94-
e.g.
95-
96-
```tsx
97-
<EngineView style={{flex: 1}} camera={camera} isTopMost={true} />
98-
```
99-
10092
To configure anti-aliasing, a property called `antiAliasing` can be changed to a value of 0 or 1 (disable anti-aliasing, default), 2, 4, 8 or 16 (anti-aliasing samples).
10193

10294
e.g.
@@ -106,3 +98,19 @@ e.g.
10698
```
10799

108100
Note: Currently only one `EngineView` can be active at any given time. Multi-view will be supported in a future release.
101+
102+
The Android specific `androidView` property can help set the type of the view used for rendering. Depending on user needs and performance, refer to the table below. [`TextureView`](https://developer.android.com/reference/android/view/TextureView) can be inserted anywhere in the view hierarchy, but is less efficient. [`SurfaceView`](https://developer.android.com/reference/android/view/SurfaceView) can only be full above or fully below the rest of the UI, but is more efficient.
103+
104+
| isTransparent | androidView | Description |
105+
| ----------- | ------------------------ | ----------- |
106+
| False | TextureView | Opaque TextureView.
107+
| False | SurfaceView | Simple surfaceView (default when no `androidView` set with `isTransparent=false`).
108+
| False | SurfaceViewZTopMost | SurfaceView with [ZTopMost](https://developer.android.com/reference/android/view/SurfaceView#setZOrderOnTop(boolean)) set to `true`.
109+
| False | SurfaceViewZMediaOverlay | SurfaceView with [ZMediaOverlay](https://developer.android.com/reference/android/view/SurfaceView#setZOrderMediaOverlay(boolean)) set to `true`.
110+
| True | TextureView | Transparent TextureView.
111+
| True | SurfaceView | SurfaceView will stay opaque
112+
| True | SurfaceViewZTopMost | SurfaceView with [ZTopMost](https://developer.android.com/reference/android/view/SurfaceView#setZOrderOnTop(boolean)) set to `true`. Transparent but top most. (default when no `androidView` set with `isTransparent=true`)
113+
| True | SurfaceViewZMediaOverlay | SurfaceView with [ZMediaOverlay](https://developer.android.com/reference/android/view/SurfaceView#setZOrderMediaOverlay(boolean)) set to `true`. Only Transparent on top of other SurfaceViews.
114+
115+
More infos on TextureView Vs SurfaceView performance here:
116+
https://developer.android.com/reference/android/view/TextureView

0 commit comments

Comments
 (0)