Auto/Custom height on Xamarin Forms WebView for Android and iOS

Xamarin Forms can sometimes be annoying with things that seem so simple and trivial, for example... Web Views can't have an automatic height set, for this you'll need a custom renderer for each device type you're building for.

A quick Google Search on dynamic height for a Xamarin Forms webview at first seems promissing, but you'll be left wanting more of the little details.

You'll more than likely find the Xamarin documentation on custom controls helpful but again lacking so more Googling would be needed.

And then you'll find this beauty of an answer given by Nevalenny on the Xamarin Forums, in this post, the forum user tells you how to set up an Extended Web View that sets its own height to the height of the content within it. All good!

In case the thread gets removed, here's the important stuff:

 

On iOS: you need to use custom Delegate (in my case it's ExtendedUIWebViewDelegate)

[assembly: ExportRenderer (typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace Core.iOS
{
    public class ExtendedWebViewRenderer : WebViewRenderer
    {      
        protected override void OnElementChanged (VisualElementChangedEventArgs e)
        {
            base.OnElementChanged (e);            
            Delegate = new ExtendedUIWebViewDelegate (this);           
        }
    }
}

then override LoadingFinished with async and small delay to get whole ContentSize.Height (in case of big content it takes some time to render even after loading is finished)

public class ExtendedUIWebViewDelegate : UIWebViewDelegate
{
    ExtendedWebViewRenderer webViewRenderer;

    public ExtendedUIWebViewDelegate (ExtendedWebViewRenderer _webViewRenderer = null)
    {
        webViewRenderer = _webViewRenderer ?? new ExtendedWebViewRenderer ();
    }     

    public override async void LoadingFinished (UIWebView webView)
    {
        var wv = webViewRenderer.Element as ExtendedWebView;
        if (wv != null) {
            await System.Threading.Tasks.Task.Delay (100); // wait here till content is rendered
            wv.HeightRequest = (double)webView.ScrollView.ContentSize.Height;
        }            
    }
}

On Android: you need to use custom Android.Webkit.WebViewClient

using WebView = Android.Webkit.WebView;
[assembly: ExportRenderer (typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace Core.Droid
{
    public class ExtendedWebViewRenderer : WebViewRenderer
    {
        static ExtendedWebView _xwebView = null;
        WebView _webView;            

        class ExtendedWebViewClient : Android.Webkit.WebViewClient
        {
            public override async void OnPageFinished (WebView view, string url)
            {
                if (_xwebView != null) {
                    int i = 10;
                    while (view.ContentHeight == 0 && i-- > 0) // wait here till content is rendered
                        await System.Threading.Tasks.Task.Delay (100);
                    _xwebView.HeightRequest = view.ContentHeight;
                }
                base.OnPageFinished (view, url);
            }
        }

        protected override void OnElementChanged (ElementChangedEventArgs e)
        {
            base.OnElementChanged (e); 
            _xwebView = e.NewElement as ExtendedWebView;
            _webView = Control;

            if (e.OldElement == null) {                
                _webView.SetWebViewClient (new ExtendedWebViewClient ());
            }         

        }        
    }
}

 

Then you'll just have to add the ExtendedWebView class somewhere in your shared library:

public class ExtendedWebView : WebView {}

That should be all you need to get the extended web view up and running right? Nope. A small detail that was left out of the post on the Xamarin forums is that if you fail to set a widthrequest and a heightrequest on the ExtendedWebView, you'll more than likely get no content render on iOS and a huge blank space below the content on Android. Useful.

Here's a snippet that shows the implementation of our ExtendedWebView within the Xamarin Forms shared code:

var Body = new ExtendedWebView();

Body.HorizontalOptions = LayoutOptions.Fill;
Body.VerticalOptions = LayoutOptions.StartAndExpand;
// Without the two below lines, the view will not render on iOS, likewise, the ExtendedWebView needs these to calculate content height.
Body.WidthRequest = 640d;
Body.HeightRequest = 640d;

var htmlSource = new HtmlWebViewSource();
htmlSource.SetBinding(HtmlWebViewSource.HtmlProperty, "HTMLDesc");
htmlSource.Html = "somehtmlcodehere";
Body.SetBinding(HtmlWebViewSource.HtmlProperty, "HTMLDesc");
Body.Source = htmlSource;
Body.BindingContextChanged += (sender, args) => {
    htmlSource.BindingContext = htmlSource.BindingContext;
};

That should be it to get it working, but if you run into trouble on iOS, you might want to try adding the following to the Info.plist file:

<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>


Published at

Tags: Xamarin

Luke Alderton

Comments

Ilya
I love you! Big thanks, you really helped this article!
10/08/2016
Alessandro
Hi Luke! In my app the first time I log in on the detail page of a news is ok, but returning to the list and returning, the height is incorrect. I use MVVM LIght
19/12/2016
Fabian
Same problem as Alessandro here!
10/05/2017
Fabian
Same problem as Alessandro here!
10/05/2017
Luke
Try putting the extended web view inside a grid, some have better luck with it when it's inside one. It can be the only element or not, shouldn't matter.
30/05/2017
Hiram
Hi Luke! Is is possible to do this for UWP. Do you have any pointer on this? Thx!
06/07/2017
Rutul Mehta
Not working inside ScrollView
04/11/2017
matt
How do you bind this to the xaml page?
17/03/2018
vikki
Hi Luke Alderton , after doing all the above steps i still getting lots of space below the content in android . if anyone have any work around for this please suggest, thanks in advance
14/06/2018
Luke
Make sure your Xamarin.Forms package is up to date within the NuGet Package Manager.
15/06/2018
Andrew
This appears to be broken on IOS 12
22/01/2021
Share with
Tags
Latest Comments
By Mark Gentry on Windows Server 2019 - Change product key does nothing
20 Aug 2021, 03:30 AM
By Cathy on In-Place Upgrade for a Windows Server domain controller
31 Jul 2021, 18:28 PM
By Mr. Greymatter on Raspberry Pi - Running Java app on Raspbian
16 Feb 2021, 07:35 AM
By Mikko Seittenranta on Xamarin Forms multiple instances of same app open
16 Feb 2021, 04:34 AM
By Andrew on Auto/Custom height on Xamarin Forms WebView for Android and iOS
22 Jan 2021, 22:15 PM
By Nick on Raspberry Pi - Running Java app on Raspbian
14 Oct 2020, 19:37 PM
By Ivan on Fixed: Value cannot be null Parameter Name: source
15 Sep 2020, 19:47 PM
By Anand on Raspberry Pi - Bluetooth using Bluecove on Raspbian
7 Sep 2020, 16:53 PM
Categories
App Development
Event
Game Development
Mapping
Modelling
Programming
Review
Robotics
Tutorial
Web Development