You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Xamarin.Forms中创建类似录屏样式的自定义弹窗?

嘿,我来帮你搞定在Xamarin.Forms里打造录屏样式的自定义弹窗这件事!下面是一步步的实现方案,从UI到原生逻辑都给你安排明白:

如何在Xamarin.Forms中创建录屏样式的自定义弹窗

第一步:搭建自定义弹窗的UI结构

我们先做一个带录屏控制按钮的弹窗UI,这里用ContentView配合Frame来模拟弹窗效果,也可以用Rg.Plugins.Popup插件简化弹窗管理,不过先讲原生实现方式:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourApp.Views.ScreenRecorderPopup">
    <Frame CornerRadius="12" Padding="20" BackgroundColor="#2D2D2D" WidthRequest="320" HeightRequest="220">
        <StackLayout Spacing="18">
            <!-- 录屏状态提示 -->
            <Label x:Name="StatusLabel" Text="准备开始录屏" TextColor="#FFFFFF" HorizontalOptions="Center" FontSize="16"/>
            <!-- 可选:实时预览区域(需要原生层传递画面) -->
            <Image x:Name="PreviewImage" HeightRequest="110" WidthRequest="190" HorizontalOptions="Center" BackgroundColor="#1A1A1A"/>
            <!-- 控制按钮组 -->
            <StackLayout Orientation="Horizontal" HorizontalOptions="Center" Spacing="25">
                <Button x:Name="StartBtn" Text="开始" Clicked="StartBtn_Clicked" 
                        BackgroundColor="#4CAF50" TextColor="White" WidthRequest="90" CornerRadius="8"/>
                <Button x:Name="StopBtn" Text="停止" Clicked="StopBtn_Clicked" 
                        BackgroundColor="#F44336" TextColor="White" WidthRequest="90" CornerRadius="8" IsEnabled="False"/>
            </StackLayout>
        </StackLayout>
    </Frame>
</ContentView>

然后写弹窗的后台逻辑,处理按钮点击和状态切换:

using Xamarin.Forms;

namespace YourApp.Views
{
    public partial class ScreenRecorderPopup : ContentView
    {
        // 定义事件,通知宿主页面录屏结束
        public event System.EventHandler<string> RecordingCompleted;

        public ScreenRecorderPopup()
        {
            InitializeComponent();
        }

        private void StartBtn_Clicked(object sender, EventArgs e)
        {
            ToggleRecordingState(true);
            DependencyService.Get<IScreenRecorder>().StartRecording();
        }

        private void StopBtn_Clicked(object sender, EventArgs e)
        {
            ToggleRecordingState(false);
            var videoPath = DependencyService.Get<IScreenRecorder>().StopRecording();
            RecordingCompleted?.Invoke(this, videoPath);
        }

        // 切换按钮状态和提示文本
        private void ToggleRecordingState(bool isRecording)
        {
            StatusLabel.Text = isRecording ? "正在录屏..." : "录屏已停止";
            StartBtn.IsEnabled = !isRecording;
            StopBtn.IsEnabled = isRecording;
        }
    }
}

第二步:定义跨平台录屏服务接口

因为Xamarin.Forms本身没有提供录屏能力,我们用依赖服务调用原生平台的API,先定义统一接口:

namespace YourApp.Services
{
    public interface IScreenRecorder
    {
        void StartRecording();
        string StopRecording(); // 返回录制好的视频文件路径
        void PauseRecording(); // 可选:添加暂停功能
    }
}

第三步:实现Android平台的录屏逻辑

Android需要用到MediaProjection和MediaRecorder,还要处理录屏权限申请,核心代码如下:

using Android.App;
using Android.Content;
using Android.Media;
using Android.OS;
using Android.Views;
using YourApp.Droid.Services;
using YourApp.Services;
using Xamarin.Forms;

[assembly: Dependency(typeof(AndroidScreenRecorder))]
namespace YourApp.Droid.Services
{
    public class AndroidScreenRecorder : IScreenRecorder
    {
        private MediaProjection _mediaProjection;
        private MediaRecorder _mediaRecorder;
        private VirtualDisplay _virtualDisplay;
        private string _outputFilePath;

        public void StartRecording()
        {
            var context = Android.App.Application.Context;
            var displayMetrics = context.Resources.DisplayMetrics;
            int screenWidth = displayMetrics.WidthPixels;
            int screenHeight = displayMetrics.HeightPixels;

            // 创建视频输出路径
            _outputFilePath = System.IO.Path.Combine(
                Android.OS.Environment.ExternalStorageDirectory.AbsolutePath,
                $"ScreenRecord_{DateTime.Now:yyyyMMddHHmmss}.mp4");

            // 初始化MediaRecorder
            _mediaRecorder = new MediaRecorder();
            _mediaRecorder.SetAudioSource(AudioSource.Mic);
            _mediaRecorder.SetVideoSource(VideoSource.Surface);
            _mediaRecorder.SetOutputFormat(OutputFormat.Mpeg4);
            _mediaRecorder.SetVideoEncoder(VideoEncoder.H264);
            _mediaRecorder.SetAudioEncoder(AudioEncoder.Aac);
            _mediaRecorder.SetVideoSize(screenWidth, screenHeight);
            _mediaRecorder.SetVideoFrameRate(30);
            _mediaRecorder.SetOutputFile(_outputFilePath);
            _mediaRecorder.Prepare();

            // 请求录屏权限(需要在MainActivity中处理回调)
            var projectionManager = (MediaProjectionManager)context.GetSystemService(Context.MediaProjectionService);
            var captureIntent = projectionManager.CreateScreenCaptureIntent();
            ((MainActivity)Forms.Context).StartActivityForResult(captureIntent, 1001);
        }

        public string StopRecording()
        {
            _mediaRecorder?.Stop();
            _mediaRecorder?.Release();
            _virtualDisplay?.Release();
            _mediaProjection?.Stop();
            return _outputFilePath;
        }

        // 供MainActivity调用,拿到权限后启动录屏
        public void StartRecordingWithProjection(MediaProjection projection)
        {
            _mediaProjection = projection;
            var displayMetrics = Android.App.Application.Context.Resources.DisplayMetrics;
            _virtualDisplay = _mediaProjection.CreateVirtualDisplay(
                "ScreenRecorder",
                displayMetrics.WidthPixels,
                displayMetrics.HeightPixels,
                displayMetrics.DensityDpi,
                DisplayFlags.Presentation,
                _mediaRecorder.Surface,
                null, null);
            _mediaRecorder.Start();
        }
    }
}

然后在MainActivity中处理权限回调:

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);
    if (requestCode == 1001 && resultCode == Result.Ok)
    {
        var projectionManager = (MediaProjectionManager)GetSystemService(Context.MediaProjectionService);
        var projection = projectionManager.GetMediaProjection((int)resultCode, data);
        DependencyService.Get<IScreenRecorder>().StartRecordingWithProjection(projection);
    }
}

第四步:实现iOS平台的录屏逻辑

iOS用ReplayKit框架实现录屏,核心代码:

using YourApp.iOS.Services;
using YourApp.Services;
using Foundation;
using ReplayKit;
using UIKit;
using Xamarin.Forms;

[assembly: Dependency(typeof(iOSScreenRecorder))]
namespace YourApp.iOS.Services
{
    public class iOSScreenRecorder : IScreenRecorder, RPPreviewViewControllerDelegate
    {
        private RPScreenRecorder _screenRecorder;
        private string _tempVideoPath;

        public iOSScreenRecorder()
        {
            _screenRecorder = RPScreenRecorder.SharedRecorder;
        }

        public void StartRecording()
        {
            if (!_screenRecorder.Available)
            {
                // 录屏不可用,提示用户
                Device.BeginInvokeOnMainThread(() =>
                {
                    Application.Current.MainPage.DisplayAlert("提示", "当前设备不支持录屏", "确定");
                });
                return;
            }

            _screenRecorder.StartRecording(new RPScreenRecorderDelegate(), (NSError error) =>
            {
                if (error != null)
                {
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        Application.Current.MainPage.DisplayAlert("错误", $"启动录屏失败:{error.LocalizedDescription}", "确定");
                    });
                }
            });
        }

        public string StopRecording()
        {
            _screenRecorder.StopRecording((previewVC, error) =>
            {
                if (error != null)
                {
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        Application.Current.MainPage.DisplayAlert("错误", $"停止录屏失败:{error.LocalizedDescription}", "确定");
                    });
                    return;
                }

                if (previewVC != null)
                {
                    previewVC.Delegate = this;
                    UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(previewVC, true, null);
                }
            });
            return _tempVideoPath;
        }

        [Export("previewControllerDidFinish:")]
        public void DidFinish(RPPreviewViewController previewViewController)
        {
            previewViewController.DismissViewController(true, null);
        }
    }
}

第五步:在页面中调用显示弹窗

在你的主页面中添加触发按钮,动态将弹窗添加到页面:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:YourApp.Views"
             x:Class="YourApp.MainPage">
    <StackLayout Padding="20" VerticalOptions="Center">
        <Button Text="打开录屏工具" Clicked="OpenRecorderPopup_Clicked" FontSize="16"/>
        <AbsoluteLayout x:Name="PopupHost" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"/>
    </StackLayout>
</ContentPage>

后台代码:

private void OpenRecorderPopup_Clicked(object sender, EventArgs e)
{
    var recorderPopup = new ScreenRecorderPopup();
    recorderPopup.RecordingCompleted += RecorderPopup_RecordingCompleted;

    // 将弹窗居中显示
    AbsoluteLayout.SetLayoutBounds(recorderPopup, new Rectangle(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
    AbsoluteLayout.SetLayoutFlags(recorderPopup, AbsoluteLayoutFlags.PositionProportional);
    
    PopupHost.Children.Add(recorderPopup);
}

private void RecorderPopup_RecordingCompleted(object sender, string videoPath)
{
    PopupHost.Children.Clear();
    DisplayAlert("录屏完成", $"视频已保存到:{videoPath}", "好的");
}

关键注意事项

  • 权限声明:Android需要在AndroidManifest.xml中添加WRITE_EXTERNAL_STORAGE、RECORD_AUDIO权限;iOS需要在Info.plist中添加NSMicrophoneUsageDescription权限描述。
  • 版本兼容性:Android 5.0(API 21)以上支持MediaProjection,iOS 9.0以上支持ReplayKit。
  • 错误处理:要添加权限拒绝、录屏不可用等场景的提示,提升用户体验。

内容的提问来源于stack exchange,提问作者Parmendra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:04:55