3
votes

I'm encountering problems getting a WebView to take up the whole screen properly in an iOS app using Xamarin Forms 4.8.0.1364 & in a ContentPage. The native control is WkWebView and am testing in an iPhone 12, iOS 14.1 Simulator.

Also, when the device rotates back into portrait orientation, the size of the WebView is wrong, or the content in the WebView is rendered improperly.

The XAML is as follows(note the BackgroundColor relative to the screencaps):

<?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>

Note: I've tried a lot of things and have removed everything that didn't make a difference. Have tried FillAndExpand on HorizontalOptions and VerticalOptions, as well as Star and Auto sizing on Grid columns/rows. I removed everything that didn't make a difference from the XAML. The results are:

Original Portrait(good enough!): WebView in opening in Portrait Mode initially

After rotating 90 to landscape: WebView after rotating 90 degrees to landscape

After rotating back to portrait(content issue?): WebView after rotating back to portrait

What I would like to see is the WebView taking up the whole screen w/ none of the various colors visible(Green, Blue, Black), and after rotation, the content should fit as expected.

I have also tried a Custom Renderer.

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

The results when calculating bounds in MyWebViewRenderer.LayoutSubviews, the results are:

Initial page load in Portrait mode: (my height calculation is off?)

Initial page load, calculated bounds

After rotate to landscape(looks ok actually):

After rotate to landscape, calculated bounds

After rotate back to portrait, the height calc is ok but somehow it's offset:

After rotate back to portrait, calculated bounds

Any suggestions?

Thanks

2
You can also add a check to see which page it is, and then keep the orientation fixed for that pageSaamer

2 Answers

2
votes

Set the width of the page to follow the screen-width of the device and VerticalOptions to FillAndExpand. See also this answer:

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);
        }
    }
  }
}
1
votes

Have a try to use WKUserScript to ensure the webpag was displayed with the same size as the screen size:

public class MyWebViewRenderer : WkWebViewRenderer
{
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);
        if (e.NewElement != null)
        {
            string jScript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";

            WKUserScript wkUScript = new WKUserScript(new NSString(jScript),WKUserScriptInjectionTime.AtDocumentEnd,true);
            WKUserContentController wkUController = new WKUserContentController();
            wkUController.AddUserScript(wkUScript);
            WKWebViewConfiguration webConfig = new WKWebViewConfiguration();

            this.Configuration.UserContentController = wkUController;
        }
    }   
}