首页 > 解决方案 > 如何在 iOS 上旋转后修复 Xamarin Forms 中的 WebView 布局(WKWebView)

问题描述

我在使用 Xamarin Forms 4.8.0.1364 和 ContentPage 的 iOS 应用程序中让 WebView 正确占据整个屏幕时遇到问题。本机控件是 WkWebView,正在 iPhone 12、iOS 14.1 模拟器中进行测试。

此外,当设备旋转回纵向时,WebView 的大小错误,或者 WebView 中的内容渲染不正确。

XAML 如下(注意相对于屏幕截图的 BackgroundColor):

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:viewModel="clr-namespace:MyCompany.MyApp.ViewModels;assembly=MyAssembly"
                x:Class="MyCompany.MyApp.Views.MyWebViewPage"
                BackgroundColor="Green" >
   <ContentPage.BindingContext>
       <viewModel:MyPageViewModel URL="https://login.somepage.com" />
   </ContentPage.BindingContext>
   <ContentPage.Content>
       <Grid BackgroundColor="Blue">
           <WebView x:Name="WebView"
                    BackgroundColor="Black"
                    Source="{Binding URL}"
                    Cookies="{Binding Cookies}">
           </WebView>
       </Grid>
   </ContentPage.Content>
</ContentPage>

注意:我已经尝试了很多东西,并删除了所有没有影响的东西。已经在 Horizo​​ntalOptions 和 VerticalOptions 上尝试过 FillAndExpand,以及在 Grid 列/行上使用 Star 和 Auto sizing。我删除了与 XAML 没有区别的所有内容。结果是:

原始肖像(足够好!):WebView 最初以纵向模式打开

旋转 90 到横向后:旋转 90 度为横向后的 WebView

旋转回纵向后(内容问题?):旋转回纵向后的 WebView

我想看到的是 WebView 占据了整个屏幕,没有各种颜色可见(绿色、蓝色、黑色),并且在旋转后,内容应该符合预期。

我也尝试过自定义渲染器。

  public class MyWebViewRenderer : WkWebViewRenderer
  {
  protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
            if (e.NewElement != null)
            {
                AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
            }
        }

        public override void LayoutSubviews()
        {
            Bounds = CalculateBounds();
         
            base.LayoutSubviews();
        }

        private CGRect CalculateBounds()
        {
            var screenBounds = UIScreen.MainScreen.Bounds;
            var statusBarHeight = UIApplication.SharedApplication.StatusBarFrame.Height;
            nfloat navBarHeight = 0;

            var uiNavController = Window?.RootViewController as UINavigationController;
            if (uiNavController?.TopViewController != null)
            {
                navBarHeight = uiNavController.NavigationBar.Bounds.Height;
            }

            var adjustedHeight = statusBarHeight + navBarHeight;

            var bounds = new CGRect(screenBounds.X, screenBounds.Y + adjustedHeight,
                screenBounds.Width, screenBounds.Height - adjustedHeight);

            return bounds;
        }
      }

MyWebViewRenderer.LayoutSubviews中计算bounds时的结果,结果为:

纵向模式下的初始页面加载:(我的高度计算已关闭?)

初始页面加载,计算范围

旋转到横向后(实际上看起来还可以):

旋转到横向后,计算边界

旋转回纵向后,高度计算没问题,但不知何故它偏移了:

旋转回纵向后,计算边界

有什么建议么?

谢谢

标签: iosxamarin.formslayoutwebviewwkwebview

解决方案


将页面的宽度设置为跟随设备的屏幕宽度并VerticalOptions设置为FillAndExpand. 另请参阅此答案

using Foundation;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using MyNamespace.iOS.Renderers;

[assembly: ExportRenderer(typeof(WebView), typeof(MyWebViewRenderer))]
namespace MyNamespace.iOS.Renderers
{
  public class MyWebViewRenderer : WkWebViewRenderer
  {
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);

        if (e.NewElement != null)
        {
            WebView webView = Element as WebView;
            webView.VerticalOptions = LayoutOptions.FillAndExpand;

            //width=device-width sets the width of the page to follow the screen-width of the device
            string jScript = @"" +
                "var meta = document.createElement('meta'); " +
                "meta.setAttribute('name', 'viewport');" +
                "meta.setAttribute('content', 'width=device-width');" +
                "document.getElementsByTagName('head')[0].appendChild(meta);";

            var userScript = new WKUserScript((NSString)jScript, WKUserScriptInjectionTime.AtDocumentEnd, true);
            
            this.Configuration.UserContentController.AddUserScript(userScript);
        }
    }
  }
}

推荐阅读