How do I make WKWebView's height fit its contents in Xamarin with a CustomWebViewRenderer?

只谈情不闲聊 提交于 2020-07-22 00:51:34

问题


I've made a Custom webview renderer for iOS where I manually replace a custom WebView with a WKWebView. However, my main purpose is to make the WKWebView adjust it's height according to it's contents. It's contents consist of predefined HTML string with body.

Right now it cuts the Webview off and the rest of the content is crammed up in a scrollview. The images and text that I put before the webview also stay fixed in place, while I want them to scroll down too. I do not want a scrollbar for the webview, I just want the webview to be true size to it's contents so that the user can swipe up to look at the entire text.

CustomWebViewRenderer.cs

[assembly: ExportRenderer(typeof(PostWebView), typeof(Yoors.iOS.CustomWebViewRenderer))]
namespace Yoors.iOS
{
    public class CustomWebViewRenderer : ViewRenderer<PostWebView, WKWebView>
    {
        WKWebView _wkWebView;
        protected override void OnElementChanged(ElementChangedEventArgs<PostWebView> e)
        {
            base.OnElementChanged(e);

            if (Control == null)
            {
                WKWebViewConfiguration config = new WKWebViewConfiguration();

                _wkWebView = new WKWebView(Frame, config);


                SetNativeControl(_wkWebView);
            }
            if (e.NewElement != null)
            {

                HtmlWebViewSource source = (Xamarin.Forms.HtmlWebViewSource)Element.Source;
                string headerString = "<header><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0'></header>";
                string html= headerString + source.Html;
                Console.WriteLine("Height" + Element);
                _wkWebView.LoadHtmlString(html, baseUrl: null);
                _wkWebView.ScrollView.ScrollEnabled = false;
                _wkWebView.SizeToFit();
            }




        }
    }

PostWebView.xaml

<?xml version="1.0" encoding="UTF-8"?>
<WebView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Yoors.Views.Templates.PostWebView" x:Name="WebViewer" BackgroundColor="White" Margin="0, 10, 0, 0" VerticalOptions="FillAndExpand" HeightRequest="1000">
    <WebView.Source>
        <HtmlWebViewSource Html="{Binding Data.Content}" />
    </WebView.Source>
</WebView>

PostView.xaml

 <ContentPage.Content>
        <ScrollView>
            <StackLayout BackgroundColor="White" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
                <!-- Header of the post-->
                <Image HeightRequest="125" Aspect="AspectFill" Source="{Binding Post.ImageUrl}" />
                <StackLayout BackgroundColor="White" Padding="1" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" Margin="10, 0,10, 0">
                    <Label Text="{Binding Post.Title}" FontFamily="{StaticResource BoldFont}" FontSize="20" />
                    <Label Text="{Binding Post.CreatedOn.DisplayText}" FontSize="12" />
                    <!-- Content of the post in a HTML view-->
                </StackLayout>
                <templates:PostWebView VerticalOptions="FillAndExpand" BindingContext="{Binding Post}">
                </templates:PostWebView>
                <templates:CommentView BindingContext="{Binding CommentsViewModel}">
                    <x:Arguments>
                        <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
                    </x:Arguments>
                </templates:CommentView>
            </StackLayout>
        </ScrollView>
    </ContentPage.Content>

I thought placing VerticalOptions= "FillAndExpand" for the PostWebView, would make it fit the size of it's contents, without creating a scollbar and therefore not fixing the other contents in place, but it just does this: Does anyone know how to help?


回答1:


I answered my own question, by making a CustomNavigationDelegate that registers when the Webview has finished loading.

CustomNavigationDelegate.cs

public class CustomWKNavigationDelegate : WKNavigationDelegate
    {

        CustomWebViewRenderer _webViewRenderer;

        public CustomWKNavigationDelegate(CustomWebViewRenderer webViewRenderer)
        {
            _webViewRenderer = webViewRenderer;
        }

        public  override async void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
       {
            var wv = _webViewRenderer.Element as PostWebView;
            if (wv != null)
            {
                await System.Threading.Tasks.Task.Delay(100); // wait here till content is rendered
                wv.HeightRequest = (double)webView.ScrollView.ContentSize.Height;
            }
        }
    }

Then in the OnElementChanged of the CustomWebViewRenderer i showed above I assign the Navigation Delegate to the WKWebView.

CustomWebViewRenderer.cs

...
 protected override void OnElementChanged(ElementChangedEventArgs<PostWebView> e)
        {
            base.OnElementChanged(e);


            if (Control == null)
            {
                WKWebViewConfiguration config = new WKWebViewConfiguration();

                _wkWebView = new WKWebView(Frame, config);
                _wkWebView.NavigationDelegate = new CustomNavigationDelegate(this);
...

This will make the WKWebView have the size of it's contents !!




回答2:


The answer above is correct, but ONLY if you do not set a higher value initially for the CustomWebView in the xaml / code behind.

I had to set some initial size in the code behind, because otherwise the webview wouldn't show up at all:

        var myDisplay = DeviceDisplay.MainDisplayInfo;
        mywebView.HeightRequest = myDisplay.Height;
        mywebView.WidthRequest = myDisplay.Width;

But with this setting, the CustomNavigationDelegate would always report the same size (2208px) which is the device display height set in the initialization. This seems to override the later recalculation. I fixed it by setting a lower initial hight, which will then dynamically adjust to the bigger required height of the content:

var myDisplay = DeviceDisplay.MainDisplayInfo;
mywebView.HeightRequest = 800;
mywebView.WidthRequest = myDisplay.Width;


来源:https://stackoverflow.com/questions/56303696/how-do-i-make-wkwebviews-height-fit-its-contents-in-xamarin-with-a-customwebvie

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!