当内容被缩小时,如何更新自定义 WebView 高度请求

3

该问题出现在Android上。

我实现了一个自定义渲染器,用于WebView根据其内容调整高度请求的能力。

我从Xamarin论坛帖子中获取了这个解决方案。

[assembly: ExportRenderer(typeof(AutoHeightWebView), typeof(AutoHeightWebViewRenderer))]
namespace MyProject.Droid.Renderers
{
    public class AutoHeightWebViewRenderer : WebViewRenderer
    {

        public AutoHeightWebViewRenderer(Context context): base(context) {}

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement is AutoHeightWebView webViewControl)
            {
                if (e.OldElement == null)
                {
                    Control.SetWebViewClient(new ExtendedWebViewClient(webViewControl));
                }
            }
        }

        class ExtendedWebViewClient : Android.Webkit.WebViewClient
        {
            private readonly AutoHeightWebView _control;

            public ExtendedWebViewClient(AutoHeightWebView control)
            {
                _control = control;
            }

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

                    _control.HeightRequest = view.ContentHeight;
                }

                base.OnPageFinished(view, url);
            }
        }
    }
}

基于某种逻辑,我更改了WebView的源代码,并使用自定义渲染器调整视图大小。

当尺寸增加时,这是有效的,但当内容尺寸小于之前的尺寸时则不行...

更明确地说,如果将WebView的源代码设置为高度为200像素的HTML文件,并将其更改为高度为1000像素的HTML文件,则可以正常工作并且可以看到所有内容。但是,如果尝试返回到200像素的HTML文件,则会在底部留下800像素的空白空间,因为视图没有更改view.ContentHeight的值,仍然保持在1000像素的值上。

我遵循了这个问题/线程,但没有找到解决此问题的解决方案:https://github.com/xamarin/Xamarin.Forms/issues/1711

我已经看到许多关于Android的主题,称我们需要重新创建Webview。是否有其他解决方案?


你尝试过将常规的 WebView 包装在一个 Grid 中,并将 RowDefinition 设置为 Auto 吗? - FabriBertani
1
是的,我必须手动调整高度才能看到内容。如果我没记错的话,内容会在视图渲染后出现,所以很可能由于文件未加载而将高度设置为0。 - Christopher St-Pierre
尝试将WebView的IsVisible设置为false,然后再设置为true。可能需要在延迟后的UI线程上执行第二个设置(= true)。这种方法可能很麻烦,但它是重新创建Webview的替代方法。 - ToolmakerSteve
@ChristopherSt-Pierre 根据您的代码,我可以重现您的问题,建议您可以从JavaScript调用C#来获取内容高度,您可以参考:https://forums.xamarin.com/discussion/160787/what-is-the-best-way-to-render-a-webview-with-source-as-htmlwebviewsource-html - Cherry Bu - MSFT
1个回答

2

我找到了一种方法,基于这个线程

我最初尝试使用JS命令返回body的高度:document.body.scrollHeight。问题是一样的,它总是返回最大的大小,但从不减小大小。

由于JS命令没有增加大小的问题,我必须将高度设置为0,设置100ms的延迟(任意),然后使用上面的JS命令获取HTML的高度并设置视图的HeightRequest

有了这个,HTML body的高度不会减少...它总是从0开始增加到HTML body的大小。

最终结果:

public class AutoHeightWebViewRenderer : WebViewRenderer
{
    static AutoHeightWebView _xwebView = null;

    public AutoHeightWebViewRenderer(Android.Content.Context context) : base(context)
    {
    }

    class DynamicSizeWebViewClient : WebViewClient
    {
        public async override void OnPageFinished(Android.Webkit.WebView view, string url)
        {
            try
            {
                if (_xwebView != null)
                {
                    view.Settings.JavaScriptEnabled = true;
                    view.Settings.DomStorageEnabled = true;
                    _xwebView.HeightRequest = 0d;

                    await Task.Delay(100);

                    string result = await _xwebView.EvaluateJavaScriptAsync("(function(){return document.body.scrollHeight;})()");
                    _xwebView.HeightRequest = Convert.ToDouble(result);
                }
                base.OnPageFinished(view, url);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"{ex.Message}");
            }
        }
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
    {
        base.OnElementChanged(e);
        _xwebView = e.NewElement as AutoHeightWebView;

        if (e.OldElement == null)
        {
            Control.SetWebViewClient(new DynamicSizeWebViewClient());
        }
    }
} 

我觉得这个答案比其他方法更好。 - Jivan Bhandari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接