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>


By Luke Alderton at 18 May 2016, 10:14 AM

Tags: Xamarin

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
Post a comment
Sit tight...
We're adding your comment.
Thank you.
Your comment has been added.
There's been a problem.
Please try again later.
Share with
Tags
Latest Comments
By dipbleds on Raspberry Pi - Bluetooth using Bluecove on Raspbian
12 Dec 2017, 21:29 PM
By Ich on Replacing the Xamarin Header/Navigation bar with a custom view/template
26 Nov 2017, 17:11 PM
By Ravi Motha on My experience at Umbraco UK Festival 2017
12 Dec 2017, 08:39 AM
By Borges on How to add a Xamarin Forms Loading Screen/Overlay
7 Nov 2017, 19:11 PM
By Rutul Mehta on Auto/Custom height on Xamarin Forms WebView for Android and iOS
4 Nov 2017, 03:15 AM
By Pablo on Xamarin MasterDetailPage has large margin/padding at top
26 Oct 2017, 15:31 PM
By faiza on Using MaryTTS or OpenMary in Java
22 Oct 2017, 12:54 PM
By Nietoperz on Using MaryTTS or OpenMary in Java
29 Sep 2017, 14:34 PM
Categories
App Development
Event
Game Development
Mapping
Modelling
Programming
Review
Robotics
Tutorial
Web Development