首页 > 解决方案 > React Native Windows - 原生 UI 组件不会显示

问题描述

我正在尝试创建一个 React Native Windows 应用程序,该应用程序使用当前未由 React Native Windows 库包装的本机 Windows 组件。特别是媒体播放器元素

我是 Windows UWP 编程和 React Native 的新手。

我按照官方文档并使用 React Native DateTimePicker项目作为参考,为 MediaPlayerElement 创建了一个 ViewManager。

代码正在编译,我可以调试以查看它正在执行,但是当 RN Windows 应用程序打开时,我看不到我的媒体播放器元素,或者在 VS Live View Tree 或 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);
    };
}

媒体播放器视图.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> {};
}

媒体播放器视图.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

应用程序.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 问题,我希望我没有给出太多的处理。

标签: javascriptuwpc++-winrtreact-native-windows

解决方案


终于找到了解决这个问题的方法!

我必须实现 Microsoft.ReactNative.IViewManagerRequiresNativeLayout 接口。从React Native Windows 文档中:

您的视图管理器还可以声明它要负责自己的大小和布局。这在包装本机 XAML 控件的情况下很有用。为此,请实现 Microsoft.ReactNative.IViewManagerRequiresNativeLayout 接口。

在我的示例中,这看起来像:


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 };
    };
}



推荐阅读