如何在 Xamarin Forms 渲染器中获取 NavigationPage 控件的 CGContext?

How to get the CGContext for a NavigationPage control in a Xamarin Forms Renderer?

我正在尝试为我的应用创建全屏覆盖。为此,我需要覆盖 NavigationPage 的渲染器,因为即使使用绝对定位,也无法将其他项目定位在导航栏上。

我有一个自定义渲染器,我正在尝试像这样绘制导航栏:

[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationPageRenderer))]
namespace MyApp.iOS.Controls
{
    public class CustomNavigationPageRenderer : NavigationRenderer
    {
        public override void ViewDidLayoutSubviews()
        {
            base.ViewDidLayoutSubviews();
            using CGContext context = UIGraphics.GetCurrentContext();
            ...
        }
    }
}

但是,上下文始终是 null。在像 this and this 这样的例子中,他们说你需要从覆盖的 Draw() 函数中调用 UIGraphics.GetCurrentContext(),但 NavigationRenderer.

中不存在这样的函数

在 Android 上可以通过覆盖 NavigationPageRenderer.DispatchDraw() 来完成,但在 iOS NavigationRenderer 上不存在。 如何在 iOS 中绘制此控件?

我们可以使用依赖服务并在根上添加半透明背景覆盖 window。

示例代码

public interface IMyInterface
{
    void present();
}

IMyInterface service = DependencyService.Get<IMyInterface>();
service.present();
[assembly: Dependency(typeof(IMyInterface))]
namespace ColeForms.iOS
{
    public class MyInterface : IMyInterface
    {

        UIView overlay;
        public MyInterface()
        {
            overlay = new UIView();

            //full screen
            overlay.Frame = UIScreen.MainScreen.Bounds;

            //translucent background 
            overlay.BackgroundColor = UIColor.FromWhiteAlpha(0.5f,0.5f);

            //add the tap gesture to dismiss overlap
            overlay.AddGestureRecognizer(new UITapGestureRecognizer(()=> {
                overlay.RemoveFromSuperview();
            }));
        }


        public void present()
        {
          UIApplication.SharedApplication.KeyWindow.RootViewController.View.Add(overlay);
        }
    }
}

屏幕截图

这是我根据上面 ColeX 的回答得出的最终解决方案

MyCustomOverlay.cs

namespace MyApp
{
    /// <summary>
    /// There's no way to "Draw" over a page in iOS, so we create a custom control that takes up the entire page and draw on that instead
    /// </summary>
    internal sealed class MyCustomOverlay : UIView
    {
        public MyCustomOverlay()
        {
            this.BackgroundColor = UIColor.Clear; // This is *required* or else the entire control is black. lol?
            AddGestureRecognizer(new UITapGestureRecognizer(RemoveFromSuperview)); // Close overlay when clicked
        }

        public override void LayoutSubviews()
        {
            base.LayoutSubviews();
            this.Frame = UIScreen.MainScreen.Bounds;
        }

        public override void Draw(CGRect rect)
        {
            base.Draw(rect);
            using CGContext context = UIGraphics.GetCurrentContext();
            // Include your draw code here
        }
    }
}

MyNavigationPageRenderer.cs


[assembly: ExportRenderer(typeof(NavigationPage), typeof(MyNavigationPageRenderer))]
namespace MyApp
{
    public class MyNavigationPageRenderer : NavigationRenderer
    {
        private UIView RootView => UIApplication.SharedApplication.KeyWindow.RootViewController.View;

        public override void ViewWillLayoutSubviews()
        {
            base.ViewWillLayoutSubviews();
            if (!RootView.Subviews.Any(o => o is MyCustomOverlay))
            {
                RootView.Add(new MyCustomOverlay());
            }
        }
    }
}