Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS WebView in a Layout does not size properly #21604

Open
czuck opened this issue Apr 2, 2024 · 5 comments
Open

iOS WebView in a Layout does not size properly #21604

czuck opened this issue Apr 2, 2024 · 5 comments
Labels
area-controls-webview WebView migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert platform/iOS 🍎 potential-regression This issue described a possible regression on a currently supported version., verification pending s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Milestone

Comments

@czuck
Copy link

czuck commented Apr 2, 2024

Description

On Android the WebView is large enough to display the content:
image

on iOS it is not:
image

Steps to Reproduce

Create a file > new Maui app. Change the MainPage.xaml to

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:cleanApp="clr-namespace:CleanApp"
             x:Class="CleanApp.MainPage">
        <VerticalStackLayout BackgroundColor="BlueViolet">
            <Label x:Name="TitleLabel"
                   FontSize="16"
                   TextColor="Black"
                   BackgroundColor="Orange"
                   VerticalOptions="Start" />
            <WebView x:Name="WebViewDescription"
                     HorizontalOptions="Fill"
                     BackgroundColor="Orange"
                     AutomationProperties.IsInAccessibleTree="False" />
        </VerticalStackLayout>
</ContentPage>

and the MainPage.xaml.cs to:

namespace CleanApp
{
    public partial class MainPage : ContentPage
    {
        public const string HtmlPage = @"<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width, initial-scale=1' /><style>{0}</style></head><body>{1}</body></html>";
        public const string MessageCss = "div.wysiwygtext p img {max-width: 100%;height: auto;}";

        public MainPage()
        {
            InitializeComponent();
            TitleLabel.Text = "Welcome to my web view test";
            WebViewDescription.Source = new HtmlWebViewSource { Html = string.Format(HtmlPage, MessageCss, "<div class=\"wysiwygtext\"><p>First Webview -  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>") };
        }
    }

}

run the app. It was found in version 8.0.14

Link to public reproduction project repository

No response

Version with bug

8.0.10 SR3

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

No response

Did you find any workaround?

No response

Relevant log output

No response

@czuck czuck added the t/bug Something isn't working label Apr 2, 2024
@AndreKraemer
Copy link
Contributor

I encountered this issue myself while migrating my initial Xamarin.Forms applications to .NET MAUI. While it can be frustrating, it's important to note that this behavior is not a bug but rather by design as the layout logic for StackLayouts got changed between Xamarin.Forms and .NET MAUI. Referencing the documentation, we find the following crucial information:

Important

A WebView must specify its HeightRequest and WidthRequest properties when contained in a HorizontalStackLayout, StackLayout, or VerticalStackLayout. If you fail to specify these properties, the WebView will not render.

In addition to setting a specific HeightRequest, another solution is to utilize a Grid instead of a VerticalStackLayout:

    <Grid BackgroundColor="BlueViolet" RowDefinitions="auto, *">
        <Label
            x:Name="TitleLabel"
            BackgroundColor="Orange"
            FontSize="16"
            TextColor="Black"
            VerticalOptions="Start" />
        <WebView
            x:Name="WebViewDescription"
            Grid.Row="1"
            AutomationProperties.IsInAccessibleTree="False"
            BackgroundColor="Orange"
            HorizontalOptions="Fill" />
    </Grid>

However, it's important to note that while this solution addresses the layout issue, the WebView will now take all the available space on the screen and may grow larger than the content, resulting in a layout that differs from your Android screenshot.

@czuck
Copy link
Author

czuck commented Apr 2, 2024

Yes, it is very frustrating that Stacked Layouts were changed so they are practically unusable and grids don't fill the gap. And the documentation is not accurate, the WebView IS rendered in both iOS and Android without either HeightRequest or WidthRequest being defined. The real issue is the WebView isn't being resized once its content is loaded on iOS. I was able to get around this using a custom handler, here it is in case anyone else can use it:

public partial class ExtendedWebViewHandler : WebViewHandler
{
    protected override void ConnectHandler(WKWebView platformView)
    {
        base.ConnectHandler(platformView);
        WebView.Loaded += OnLoaded;
    }


    protected override void DisconnectHandler(WKWebView platformView)
    {
        WebView.Loaded -= OnLoaded;
        base.DisconnectHandler(platformView);
    }

    WebView WebView => VirtualView as WebView;


    private void OnLoaded(object sender, EventArgs e)
    {
        PlatformView.NavigationDelegate = new ExtendedWKNavigationDelegate(WebView);

        // For fixing white flash issue in webview on dark themes/backgrounds and disable webview's scrolling
        PlatformView.Opaque = false;
        PlatformView.BackgroundColor = UIColor.Clear;
        PlatformView.ScrollView.ScrollEnabled = false;
    }

    class ExtendedWKNavigationDelegate: WKNavigationDelegate
    {
        private WebView _webView;
        public ExtendedWKNavigationDelegate(WebView webview)
        {
            _webView = webview;
        }
        public override async void DidFinishNavigation(WKWebView platformView, WKNavigation navigation)
        {
            while (platformView.IsLoading)
            {
                await Task.Delay(100); // wait here till content is rendered
            }
            _webView.HeightRequest = platformView.ScrollView.ContentSize.Height;
        }
    }

@ninachen03 ninachen03 added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed potential-regression This issue described a possible regression on a currently supported version., verification pending labels Apr 3, 2024
@ninachen03
Copy link

Can repro this issue at iOS platform on the latest 17.10.0 preview2 (8.0.14 & 8.0.7).
image

@mattleibow mattleibow added this to the Backlog milestone Apr 3, 2024
@mattleibow mattleibow added legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor area-controls-webview WebView labels Apr 3, 2024
@samhouts samhouts added the migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert label Apr 22, 2024
@Eilon Eilon removed the legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor label May 10, 2024
@thedee
Copy link

thedee commented May 17, 2024

I have the same issue. The problem with our situation is that we can't set a Height because the data is dynamic and can change. So setting a HeightReqeust to 50 or whatever will not work.

@czuck I tried your example but for some reason the DidFinishNavigation is never firing. This used to fire in Xamarin but not in Maui.

UPDATE
The reason why my DidFinishNavigation wasn't firing is because I was mapping to the source.
public static PropertyMapper<MyWebView, MyWebViewHandler> PropertyMapper = new PropertyMapper<MyWebView,
MyWebViewHandler>(WebViewHandler.Mapper)
{
[nameof(MyWebView.Source)] = MapSource,
};

Once I took that out the webView loaded. I then still had the issue of resizing. When the code executed this line:
_webView.HeightRequest = platformView.ScrollView.ContentSize.Height;

The height was 0. If I added a 5 second delay just before this line it works. The reason why is because once the page is loaded on the screen and showing, it then would show the contentsize correctly. If you try and get the size before the actual page is showing on the device then it just says 0.

@samhouts samhouts removed s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed labels Jul 3, 2024
@samhouts samhouts added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed labels Jul 10, 2024
@imoulas
Copy link

imoulas commented Aug 19, 2024

A decent workaround is to get the size of the whole page even if is not shown completely via javascript.

You can add to your bottom of your web page the following code:

<div id=""page-height""></div>

<script>
      const body = document.body; 
      const html = document.documentElement;      
      const height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);    
      document.getElementById('page-height').innerHTML = height;
</script>

and after the page loads you can call the following code to get the calculated height from the page:

yourpage.xaml

 <WebView x:Name="yourwebview">
      <WebView.Source>
          <HtmlWebViewSource Html="{Binding exampleHtml}" />
      </WebView.Source>
  </WebView>

yourpage.xaml.cs

var result = await yourwebview.EvaluateJavaScriptAsync($"document.getElementById('page-height').innerText");
Console.WriteLine(result);
yourwebview.HeightRequest = Convert.ToDouble(result.ToString());

I hope that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-webview WebView migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert platform/iOS 🍎 potential-regression This issue described a possible regression on a currently supported version., verification pending s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

8 participants