我正在创建一个React原生Android应用程序,我想嵌入一个使用Vulkan呈现的控件。我通过创建
SurfaceView
调用
VkSurfaceView
并使用JNI调用在Rust中实现Vulkan代码。
我打开了显示所有视图边界的调试设置,这样可以清楚地看到视图仍然存在。
以下是简单Android布局(无React Native)中的Vulkan控件(目前仅呈现三角形):
这是我没有Vulkan控件的React原生布局(方形代表我试图放置Vulkan控件的位置):
但当我放置Vulkan控件时,其他所有内容都会变暗,即使布局检查器和调试覆盖显示其他视图仍然存在:
为什么会发生这种情况?如上所示,Vulkan控件在纯Android布局中工作,因此我认为它一定以某种方式与React Native进行了不利的交互。然而,我发现了这样的例子
this
和
this
能够使用
表面视图
/
TextureView
/
VideoView
在React Native中,不会导致问题。
编辑:
即使我注释掉了
VkSurfaceView
,黑屏问题仍然存在(但三角形显然消失了),所以我不认为这是因为我的Vulkan代码存在问题。
编辑2:
如果我从
纹理视图
而不是
表面视图
.但为什么?我怀疑这与所解释的差异有关
here
,但我仍然不明白为什么视图是否使用OpenGL合成很重要。
这是我的代码:
反应本机
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
);
反应本机
surface-view.js
:
import { requireNativeComponent } from 'react-native';
module.exports = requireNativeComponent('SPVkSurfaceView');
JAVA
SurfaceReactPackage.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)
);
}
}
JAVA
ReactSurfaceManager.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;
}
}
JAVA
MainActivity.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();
}
}
}