React Native Windows - Native UI 组件不会显示
React Native Windows - Native UI Component wont Display
我正在尝试创建一个 React Native Windows 应用程序,它使用当前未被 React Native Windows 库包装的本机 Windows 组件。具体来说 Media Player Element.
我是 Windows UWP 编程和 React Native 的新手。
我在 offical documentation and using the React Native DateTimePicker 项目之后为 MediaPlayerElement 创建了一个 ViewManager 作为参考。
代码正在编译,我可以调试以查看它是否正在执行,但是当 RN Windows 应用程序打开时,我看不到我的媒体播放器元素,或者在 VS 实时视图树或 React Native 中看不到我的媒体播放器元素树视图工具。
我已经使用 .idl 文件包装了 MediaPlayerElement,这由我的 MediaPlayerViewManager 调用,它将视图暴露给 React Native。
我的代码片段如下:
MediaPlayerView.idl
namespace MediaPlayer {
[default_interface]
runtimeclass MediaPlayerView : Windows.UI.Xaml.Controls.MediaPlayerElement {
MediaPlayerView(Microsoft.ReactNative.IReactContext context);
void UpdateProperties(Microsoft.ReactNative.IJSValueReader reader);
};
}
MediaPlayerView.h
#include "NativeModules.h"
#include "Generated Files/MediaPlayer.MediaPlayerView.g.h"
namespace winrt::MediaPlayer::implementation {
namespace xaml = winrt::Windows::UI::Xaml;
class MediaPlayerView : public MediaPlayerViewT<MediaPlayerView> {
public:
MediaPlayerView(Microsoft::ReactNative::IReactContext const& reactContext);
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const& reader);
private:
Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
bool m_updating{ false };
void RegisterEvents();
};
}
namespace winrt::MediaPlayer::factory_implementation {
struct MediaPlayerView : MediaPlayerViewT<MediaPlayerView, implementation::MediaPlayerView> {};
}
MediaPlayerView.cpp
#include "pch.h"
#include "JSValueXaml.h"
#include "MediaPlayerView.h"
#include "Generated Files/MediaPlayer.MediaPlayerView.g.cpp"
namespace winrt {
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation;
}
namespace winrt::MediaPlayer::implementation {
MediaPlayerView::MediaPlayerView(winrt::IReactContext const& reactContext) :
m_reactContext(reactContext) {
RegisterEvents();
}
void MediaPlayerView::RegisterEvents() {
// TODO:Register events.
}
void MediaPlayerView::UpdateProperties(winrt::IJSValueReader const& reader) {
m_updating = true;
// TODO:Update properties.
m_updating = false;
return;
}
}
MediaPlayerViewManager.h
#pragma once
#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"
namespace winrt::MediaPlayer::implementation {
class MediaPlayerViewManager : public winrt::implements<
MediaPlayerViewManager,
winrt::Microsoft::ReactNative::IViewManager,
winrt::Microsoft::ReactNative::IViewManagerWithReactContext,
winrt::Microsoft::ReactNative::IViewManagerWithNativeProperties,
winrt::Microsoft::ReactNative::IViewManagerWithExportedEventTypeConstants> {
public:
MediaPlayerViewManager();
// IViewManager
winrt::hstring Name() noexcept;
winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
// IViewManagerWithReactContext
winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
void ReactContext(winrt::Microsoft::ReactNative::IReactContext reactContext) noexcept;
// IViewManagerWithNativeProperties
winrt::Windows::Foundation::Collections::
IMapView<winrt::hstring, winrt::Microsoft::ReactNative::ViewManagerPropertyType>
NativeProps() noexcept;
void UpdateProperties(
winrt::Windows::UI::Xaml::FrameworkElement const& view,
winrt::Microsoft::ReactNative::IJSValueReader const& propertyMapReader) noexcept;
// IViewManagerWithExportedEventTypeConstants
winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomBubblingEventTypeConstants() noexcept;
winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomDirectEventTypeConstants() noexcept;
private:
winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
};
}
MediaPlayerViewManager.cpp
#include "pch.h"
#include "MediaPlayerViewManager.h"
#include "NativeModules.h"
#include "MediaPlayerView.h"
namespace winrt {
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation::Collections;
namespace xaml = winrt::Windows::UI::Xaml;
}
namespace winrt::MediaPlayer::implementation {
MediaPlayerViewManager::MediaPlayerViewManager() {}
//IViewManager
winrt::hstring MediaPlayerViewManager::Name() noexcept {
return L"MediaPlayerView";
}
xaml::FrameworkElement MediaPlayerViewManager::CreateView() noexcept {
return winrt::MediaPlayer::MediaPlayerView(m_reactContext);
}
// IViewManagerWithReactContext
winrt::IReactContext MediaPlayerViewManager::ReactContext() noexcept {
return m_reactContext;
}
void MediaPlayerViewManager::ReactContext(IReactContext reactContext) noexcept {
m_reactContext = reactContext;
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> MediaPlayerViewManager::NativeProps() noexcept {
auto nativeProps = winrt::single_threaded_map<hstring, ViewManagerPropertyType>();
// Insert native props here:
return nativeProps.GetView();
}
void MediaPlayerViewManager::UpdateProperties(xaml::FrameworkElement const& view,
IJSValueReader const& propertyMapReader) noexcept {
if (auto mediaPlayerView = view.try_as<MediaPlayerView>()) {
mediaPlayerView->UpdateProperties(propertyMapReader);
} else {
OutputDebugStringW(L"Type deduction for MediaPlayerView failed.");
}
}
// IViewManagerWithExportedEventTypeConstants
ConstantProviderDelegate MediaPlayerViewManager::ExportedCustomBubblingEventTypeConstants() noexcept {
return nullptr;
}
ConstantProviderDelegate MediaPlayerViewManager::ExportedCustomDirectEventTypeConstants() noexcept {
return nullptr;
}
}
ReactPackageProvider.cpp
#include "pch.h"
#include "ReactPackageProvider.h"
#include "NativeModules.h"
using namespace winrt::Microsoft::ReactNative;
// NOTE: You must include the headers of your native modules here in
// order for the AddAttributedModules call below to find them.
#include "MediaPlayerViewManager.h"
namespace winrt::MediaPlayerProject::implementation
{
void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
{
AddAttributedModules(packageBuilder);
packageBuilder.AddViewManager(L"MediaPlayerViewManager", []() { return winrt::make<winrt::MediaPlayer::implementation::MediaPlayerViewManager>(); });
}
} // namespace winrt::MediaPlayerProject::implementation
MediaPlayerView.js
import React from 'react';
import { StyleSheet, View} from 'react-native';
import { requireNativeComponent } from 'react-native';
const MediaPlayerWindows = requireNativeComponent("MediaPlayerView")
const MediaPlayerView = () => {
return(
<View style={styles.container}>
<MediaPlayerWindows/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex:1,
justifyContent:'center',
alignItems:'center',
}
})
export default MediaPlayerView
App.tsx
import React from 'react';
import {
SafeAreaView,
StyleSheet,
} from 'react-native';
import MediaPlayerView from './components/MediaPlayerView';
const App = () => {
return (
<SafeAreaView style={styles.App}>
<MediaPlayerView/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
App: {
flexDirection:"column",
flex:1,
alignItems: 'center',
justifyContent:'center',
}
});
export default App;
看不到 React Native 的任何输出我做错了什么 Windows?
感谢您阅读到这里。这是我的第一个 Stack Overflow 问题,我希望我没有给出太多需要处理的问题。
终于找到解决方法了!
我必须实现 Microsoft.ReactNative.IViewManagerRequiresNativeLayout 接口。
来自 React Native Windows documentation:
Your view manager is also able to declare that it wants to be
responsible for its own sizing and layout. This is useful in scenarios
where you are wrapping a native XAML control. To do so, implement the
Microsoft.ReactNative.IViewManagerRequiresNativeLayout interface.
在我的例子中,这看起来像:
MediaPlayerViewManager.h
#pragma once
#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"
namespace winrt::MediaPlayer::implementation {
class MediaPlayerViewManager : public winrt::implements<
MediaPlayerViewManager,
winrt::Microsoft::ReactNative::IViewManager,
winrt::Microsoft::ReactNative::IViewManagerRequiresNativeLayout> {
public:
MediaPlayerViewManager();
// IViewManager
winrt::hstring Name() noexcept;
winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
// IViewManagerRequiresNativeLayout
bool RequiresNativeLayout() { return true; }
private:
winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
};
}
我正在尝试创建一个 React Native Windows 应用程序,它使用当前未被 React Native Windows 库包装的本机 Windows 组件。具体来说 Media Player Element.
我是 Windows UWP 编程和 React Native 的新手。
我在 offical documentation and using the React Native DateTimePicker 项目之后为 MediaPlayerElement 创建了一个 ViewManager 作为参考。
代码正在编译,我可以调试以查看它是否正在执行,但是当 RN Windows 应用程序打开时,我看不到我的媒体播放器元素,或者在 VS 实时视图树或 React Native 中看不到我的媒体播放器元素树视图工具。
我已经使用 .idl 文件包装了 MediaPlayerElement,这由我的 MediaPlayerViewManager 调用,它将视图暴露给 React Native。
我的代码片段如下:
MediaPlayerView.idl
namespace MediaPlayer {
[default_interface]
runtimeclass MediaPlayerView : Windows.UI.Xaml.Controls.MediaPlayerElement {
MediaPlayerView(Microsoft.ReactNative.IReactContext context);
void UpdateProperties(Microsoft.ReactNative.IJSValueReader reader);
};
}
MediaPlayerView.h
#include "NativeModules.h"
#include "Generated Files/MediaPlayer.MediaPlayerView.g.h"
namespace winrt::MediaPlayer::implementation {
namespace xaml = winrt::Windows::UI::Xaml;
class MediaPlayerView : public MediaPlayerViewT<MediaPlayerView> {
public:
MediaPlayerView(Microsoft::ReactNative::IReactContext const& reactContext);
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const& reader);
private:
Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
bool m_updating{ false };
void RegisterEvents();
};
}
namespace winrt::MediaPlayer::factory_implementation {
struct MediaPlayerView : MediaPlayerViewT<MediaPlayerView, implementation::MediaPlayerView> {};
}
MediaPlayerView.cpp
#include "pch.h"
#include "JSValueXaml.h"
#include "MediaPlayerView.h"
#include "Generated Files/MediaPlayer.MediaPlayerView.g.cpp"
namespace winrt {
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation;
}
namespace winrt::MediaPlayer::implementation {
MediaPlayerView::MediaPlayerView(winrt::IReactContext const& reactContext) :
m_reactContext(reactContext) {
RegisterEvents();
}
void MediaPlayerView::RegisterEvents() {
// TODO:Register events.
}
void MediaPlayerView::UpdateProperties(winrt::IJSValueReader const& reader) {
m_updating = true;
// TODO:Update properties.
m_updating = false;
return;
}
}
MediaPlayerViewManager.h
#pragma once
#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"
namespace winrt::MediaPlayer::implementation {
class MediaPlayerViewManager : public winrt::implements<
MediaPlayerViewManager,
winrt::Microsoft::ReactNative::IViewManager,
winrt::Microsoft::ReactNative::IViewManagerWithReactContext,
winrt::Microsoft::ReactNative::IViewManagerWithNativeProperties,
winrt::Microsoft::ReactNative::IViewManagerWithExportedEventTypeConstants> {
public:
MediaPlayerViewManager();
// IViewManager
winrt::hstring Name() noexcept;
winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
// IViewManagerWithReactContext
winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
void ReactContext(winrt::Microsoft::ReactNative::IReactContext reactContext) noexcept;
// IViewManagerWithNativeProperties
winrt::Windows::Foundation::Collections::
IMapView<winrt::hstring, winrt::Microsoft::ReactNative::ViewManagerPropertyType>
NativeProps() noexcept;
void UpdateProperties(
winrt::Windows::UI::Xaml::FrameworkElement const& view,
winrt::Microsoft::ReactNative::IJSValueReader const& propertyMapReader) noexcept;
// IViewManagerWithExportedEventTypeConstants
winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomBubblingEventTypeConstants() noexcept;
winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomDirectEventTypeConstants() noexcept;
private:
winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
};
}
MediaPlayerViewManager.cpp
#include "pch.h"
#include "MediaPlayerViewManager.h"
#include "NativeModules.h"
#include "MediaPlayerView.h"
namespace winrt {
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation::Collections;
namespace xaml = winrt::Windows::UI::Xaml;
}
namespace winrt::MediaPlayer::implementation {
MediaPlayerViewManager::MediaPlayerViewManager() {}
//IViewManager
winrt::hstring MediaPlayerViewManager::Name() noexcept {
return L"MediaPlayerView";
}
xaml::FrameworkElement MediaPlayerViewManager::CreateView() noexcept {
return winrt::MediaPlayer::MediaPlayerView(m_reactContext);
}
// IViewManagerWithReactContext
winrt::IReactContext MediaPlayerViewManager::ReactContext() noexcept {
return m_reactContext;
}
void MediaPlayerViewManager::ReactContext(IReactContext reactContext) noexcept {
m_reactContext = reactContext;
}
// IViewManagerWithNativeProperties
IMapView<hstring, ViewManagerPropertyType> MediaPlayerViewManager::NativeProps() noexcept {
auto nativeProps = winrt::single_threaded_map<hstring, ViewManagerPropertyType>();
// Insert native props here:
return nativeProps.GetView();
}
void MediaPlayerViewManager::UpdateProperties(xaml::FrameworkElement const& view,
IJSValueReader const& propertyMapReader) noexcept {
if (auto mediaPlayerView = view.try_as<MediaPlayerView>()) {
mediaPlayerView->UpdateProperties(propertyMapReader);
} else {
OutputDebugStringW(L"Type deduction for MediaPlayerView failed.");
}
}
// IViewManagerWithExportedEventTypeConstants
ConstantProviderDelegate MediaPlayerViewManager::ExportedCustomBubblingEventTypeConstants() noexcept {
return nullptr;
}
ConstantProviderDelegate MediaPlayerViewManager::ExportedCustomDirectEventTypeConstants() noexcept {
return nullptr;
}
}
ReactPackageProvider.cpp
#include "pch.h"
#include "ReactPackageProvider.h"
#include "NativeModules.h"
using namespace winrt::Microsoft::ReactNative;
// NOTE: You must include the headers of your native modules here in
// order for the AddAttributedModules call below to find them.
#include "MediaPlayerViewManager.h"
namespace winrt::MediaPlayerProject::implementation
{
void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
{
AddAttributedModules(packageBuilder);
packageBuilder.AddViewManager(L"MediaPlayerViewManager", []() { return winrt::make<winrt::MediaPlayer::implementation::MediaPlayerViewManager>(); });
}
} // namespace winrt::MediaPlayerProject::implementation
MediaPlayerView.js
import React from 'react';
import { StyleSheet, View} from 'react-native';
import { requireNativeComponent } from 'react-native';
const MediaPlayerWindows = requireNativeComponent("MediaPlayerView")
const MediaPlayerView = () => {
return(
<View style={styles.container}>
<MediaPlayerWindows/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex:1,
justifyContent:'center',
alignItems:'center',
}
})
export default MediaPlayerView
App.tsx
import React from 'react';
import {
SafeAreaView,
StyleSheet,
} from 'react-native';
import MediaPlayerView from './components/MediaPlayerView';
const App = () => {
return (
<SafeAreaView style={styles.App}>
<MediaPlayerView/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
App: {
flexDirection:"column",
flex:1,
alignItems: 'center',
justifyContent:'center',
}
});
export default App;
看不到 React Native 的任何输出我做错了什么 Windows?
感谢您阅读到这里。这是我的第一个 Stack Overflow 问题,我希望我没有给出太多需要处理的问题。
终于找到解决方法了!
我必须实现 Microsoft.ReactNative.IViewManagerRequiresNativeLayout 接口。 来自 React Native Windows documentation:
Your view manager is also able to declare that it wants to be responsible for its own sizing and layout. This is useful in scenarios where you are wrapping a native XAML control. To do so, implement the Microsoft.ReactNative.IViewManagerRequiresNativeLayout interface.
在我的例子中,这看起来像:
MediaPlayerViewManager.h
#pragma once
#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"
namespace winrt::MediaPlayer::implementation {
class MediaPlayerViewManager : public winrt::implements<
MediaPlayerViewManager,
winrt::Microsoft::ReactNative::IViewManager,
winrt::Microsoft::ReactNative::IViewManagerRequiresNativeLayout> {
public:
MediaPlayerViewManager();
// IViewManager
winrt::hstring Name() noexcept;
winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
// IViewManagerRequiresNativeLayout
bool RequiresNativeLayout() { return true; }
private:
winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
};
}