【发布时间】:2021-12-20 05:49:52
【问题描述】:
我正在创建一个 React Native Android 应用程序,并且我想嵌入一个使用 Vulkan 呈现的控件。我通过创建一个名为 VkSurfaceView 的 SurfaceView 的子类并使用 JNI 调用在 Rust 中实现 Vulkan 代码来实现此控制。
我打开了显示所有视图边界的调试设置,以便清楚地看到视图仍然存在。
这是一个简单的 Android 布局(无 React Native)内的 Vulkan 控件(目前,它只呈现一个三角形):
这是我没有 Vulkan 控件的 React Native 布局(正方形代表我试图放置 Vulkan 控件的位置):
但是当我放置 Vulkan 控件时,其他一切都变暗了,即使布局检查器和调试覆盖显示其他视图仍然存在:
为什么会发生这种情况?如上所示,Vulkan 控件在纯 Android 布局中工作,所以我认为它一定会以某种方式与 React Native 进行不利的交互。但是,我发现像 this 和 this 这样的例子可以在 React Native 中使用 SurfaceView/TextureView/VideoView 而不会引起问题。
编辑:即使我注释掉VkSurfaceView中的所有代码,黑屏问题仍然存在(但三角形显然消失了),所以我认为不会发生这种情况因为我的 Vulkan 代码有问题。
编辑 2: 如果我从 TextureView 派生而不是 SurfaceView 派生,它会起作用。但为什么?我怀疑这与here 解释的差异有关,但我仍然不明白为什么视图是否使用 OpenGL 合成很重要。
这是我的代码:
React Native index.js:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import VkSurfaceView from './surface-view';
const HelloWorld = () => {
return (
<View style={[styles.container, {
// Try setting `flexDirection` to `"row"`.
flexDirection: "column"
}]}>
<Text style={styles.hello}>Hello, World</Text>
<View style={{ width: 100, height: 100, alignSelf: 'center', backgroundColor: 'pink' }}>
<VkSurfaceView style={{ width: 100, height: 100 }}/>
</View>
</View>
);
};
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ffffff'
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
color: 'green'
}
});
AppRegistry.registerComponent(
'MyReactNativeApp',
() => HelloWorld
);
React Native surface-view.js:
import { requireNativeComponent } from 'react-native';
module.exports = requireNativeComponent('SPVkSurfaceView');
JavaSurfaceReactPackage.java:
public class SurfaceReactPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@NonNull
@Override
public List<ViewManager> createViewManagers(
@NonNull ReactApplicationContext reactContext) {
return Collections.singletonList(
new ReactSurfaceManager(reactContext)
);
}
}
JavaReactSurfaceManager.java:
public class ReactSurfaceManager extends SimpleViewManager<VkSurfaceView> {
public static final String REACT_CLASS = "SPVkSurfaceView";
ReactApplicationContext mCallerContext;
public ReactSurfaceManager(ReactApplicationContext reactContext) {
mCallerContext = reactContext;
}
@NonNull
@Override
public VkSurfaceView createViewInstance(ThemedReactContext context) {
return new VkSurfaceView(context);
}
@Override
public String getName() {
return REACT_CLASS;
}
}
JavaMainActivity.java
public class MainActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// initialize native code library before using VkSurfaceView
MyNativeLibary.init();
// initialize React Native
mReactRootView = new ReactRootView(this);
List<ReactPackage> packages = new PackageList(getApplication()).getPackages();
packages.add(new SurfaceReactPackage());
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setCurrentActivity(this)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackages(packages)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
// The string here (e.g. "MyReactNativeApp") has to match
// the string in AppRegistry.registerComponent() in index.js
mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);
setContentView(mReactRootView);
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy(this);
}
if (mReactRootView != null) {
mReactRootView.unmountReactApplication();
}
}
@Override
public void invokeDefaultOnBackPressed() {
this.onBackPressed();
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
}
【问题讨论】:
标签: android react-native surfaceview vulkan