2
votes

Comment faire en sorte que la hauteur de WKWebView corresponde à son contenu dans Xamarin avec un CustomWebViewRenderer?

J'ai créé un moteur de rendu de vue Web personnalisé pour iOS dans lequel je remplace manuellement une WebView personnalisée par une WKWebView. Cependant, mon objectif principal est de faire en sorte que le WKWebView ajuste sa hauteur en fonction de son contenu. Son contenu se compose d'une chaîne HTML prédéfinie avec un corps.

À l'heure actuelle, il coupe la Webview et le reste du contenu est entassé dans un scrollview. Les images et le texte que j'ai mis avant la vue Web restent également fixes, alors que je veux qu'ils défilent également vers le bas. Je ne veux pas de barre de défilement pour la vue Web, je veux juste que la vue Web soit à la taille réelle de son contenu afin que l'utilisateur puisse glisser vers le haut pour regarder le texte entier.

CustomWebViewRenderer.cs

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

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

[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();
            }




        }
    }

Je pensais que placer VerticalOptions = "FillAndExpand" pour PostWebView, le ferait correspondre à la taille de son contenu, sans créer de barre de défilement et donc ne pas fixer les autres contenus en place, mais il fait juste ceci: [! [ceci] [1]] [1]. Quelqu'un sait-il comment aider?


0 commentaires

3 Réponses :


2
votes

J'ai répondu à ma propre question, en créant un CustomNavigationDelegate qui s'enregistre lorsque le Webview a fini de se charger.

CustomNavigationDelegate.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);
...

Ensuite, dans le OnElementChanged du CustomWebViewRenderer que j'ai montré ci-dessus, j'attribue le délégué de navigation au WKWebView.

CustomWebViewRenderer.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;
            }
        }
    }

Cela donnera à WKWebView la taille de son contenu !!


2 commentaires

J'obtiens un <cast spécifié n'est pas valide> en ligne: HtmlWebViewSource source = (Xamarin.Forms.HtmlWebViewSource) Element.Source;


DidFinishNavigation n'est pas touché pour moi. Des solutions? Merci



1
votes

La réponse ci-dessus est correcte, mais UNIQUEMENT si vous ne définissez pas initialement une valeur supérieure pour le CustomWebView dans le xaml / code derrière.

J'ai dû définir une taille initiale dans le code derrière, car sinon la vue Web ne s'afficherait pas du tout:

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

Mais avec ce paramètre, CustomNavigationDelegate signalera toujours la même taille (2208px) qui est la hauteur d'affichage de l'appareil définie lors de l'initialisation. Cela semble remplacer le recalcul ultérieur. Je l'ai corrigé en définissant une hauteur initiale inférieure, qui s'ajustera ensuite dynamiquement à la plus grande hauteur requise du contenu:

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


0 commentaires

0
votes

Auparavant, j'avais un écran blanc dans la zone de visualisation Web et la hauteur dynamique ne fonctionnait pas. Mais maintenant, cela fonctionne bien! Également publié ici - https://github.com/xamarin/Xamarin.Forms/issues/1711

[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace Project.iOS.Renderers
{
    class ExtendedWebViewRenderer : WkWebViewRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            try
            {
                base.OnElementChanged(e);

                NavigationDelegate = new ExtendedWKWebViewDelegate(this);

                // For fixing white flash issue in webview on dark themes/backgrounds and disable webview's scrolling
                if (NativeView != null)
                {
                   var webView = (WKWebView)NativeView;

                   webView.Opaque = false;
                   webView.BackgroundColor = UIColor.Clear;
                   webView.ScrollView.ScrollEnabled = false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error at ExtendedWebViewRenderer OnElementChanged: " + ex.Message);
            }
        }
    }

    class ExtendedWKWebViewDelegate : WKNavigationDelegate
    {
        ExtendedWebViewRenderer webViewRenderer;

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

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


0 commentaires