问题
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