自动调整WebView的大小以适合内容

Dan*_*Dan 5 c# xamarin.ios xamarin.android xamarin xamarin.forms

我正在研究Xamarin.Forms PCL项目,该项目以WebView的形式显示帖子,因此我添加了可点击的内容(例如#标签)。

我遇到的问题是WebView不能适应其内容的大小。WebView不会加载实际的网站,我正在使用以下方法将HTML绑定到ListView中的每个帖子

"<html><p>" + body + "</p></html>"

我尝试研究自定义渲染器,并按照本教程进行操作,最后得到以下代码

我使用的Android

#pragma warning disable CS0618 // Type or member is obsolete
public class CustomWebViewAndroid : WebViewRenderer
{
    static CustomWebView _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<Xamarin.Forms.WebView> e)
    {
        base.OnElementChanged (e); 
        _xwebView = e.NewElement as CustomWebView;
        _webView = Control;

        if (e.OldElement == null) {                
            _webView.SetWebViewClient (new ExtendedWebViewClient ());
        }         

    }       
}
Run Code Online (Sandbox Code Playgroud)

对于iOS

public class CustomWebViewiOS : WebViewRenderer
{
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);
        Delegate = new CustomWebViewDelegate(this);
    }
}

public class CustomWebViewDelegate : UIWebViewDelegate
{
    CustomWebViewiOS webViewRenderer;

    public CustomWebViewDelegate(CustomWebViewiOS _webViewRenderer = null)
    {
        webViewRenderer = _webViewRenderer ?? new CustomWebViewiOS();
    }

    public override async void LoadingFinished(UIWebView webView)
    {
        var wv = webViewRenderer.Element as CustomWebView;
        if (wv != null)
        {
            await System.Threading.Tasks.Task.Delay(100); // wait here till content is rendered
            wv.HeightRequest = (double)webView.ScrollView.ContentSize.Height;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样在XAML中应用它

<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
    <local:CustomWebView HeightRequest="20" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
        <local:CustomWebView.Source>
            <HtmlWebViewSource Html="{Binding HtmlContent}"/>
        </local:CustomWebView.Source>
    </local:CustomWebView>
</StackLayout>
Run Code Online (Sandbox Code Playgroud)

在Android上,它会剪掉帖子的一半。

Android示例

在iOS上,它无法正确间隔帖子的位置,并切断了其上方的时间戳。我的猜测是ViewCell的高度会根据内容进行调整,但没有考虑其他帖子。同样对于iOS,如果文本需要两行,则需要滚动查看其余内容。

iOS示例

Lan*_*SFT 6

首先,您应该将ListView设置HasUnevenRows为true,然后建议您使用XAML Grid包装webView并删除其中HeightRequest的内容。您可以参考我的XAML:

<local:MyListView x:Name="MyListView" HasUnevenRows="True">
    <local:MyListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid>
                    <local:AutoWebView>
                        <local:AutoWebView.Source>
                            <HtmlWebViewSource Html="{Binding}"/>
                        </local:AutoWebView.Source>
                    </local:AutoWebView>
                </Grid>
            </ViewCell>
        </DataTemplate>
    </local:MyListView.ItemTemplate>
</local:MyListView>
Run Code Online (Sandbox Code Playgroud)

对于您的Android渲染器:

当我们获得实际值时,请勿在中使用静态标识符,_xwebView并刷新使用方法,例如:LoadingFinished()HeightRequestViewCellForceUpdateSize()

public class MyWebViewAndroidRenderer : WebViewRenderer
{
    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        Control.SetWebViewClient(new ExtendedWebViewClient(Element as AutoWebView));

    }

    class ExtendedWebViewClient : Android.Webkit.WebViewClient
    {
        AutoWebView xwebView;
        public ExtendedWebViewClient(AutoWebView webView)
        {
            xwebView = webView;
        }

        async public override void OnPageFinished(Android.Webkit.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;
                // Here use parent to find the ViewCell, you can adjust the number of parents depending on your XAML
                (xwebView.Parent.Parent as ViewCell).ForceUpdateSize();
            }

            base.OnPageFinished(view, url);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于iOS:

当webView加载完成时,我们还需要刷新单元格:

public override void LoadingFinished(UIWebView webView)
{
    var wv = webViewRenderer.Element as AutoWebView;
    if (wv.HeightRequest < 0)
    {
        wv.HeightRequest = (double)webView.ScrollView.ContentSize.Height;
        (wv.Parent.Parent as ViewCell).ForceUpdateSize();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • Xamarin Live Player不是为调试而设计的,它只是临时显示一些视图。尤其是使用渲染器时,存在一些限制。但这在模拟器或真实设备上可以正常工作。请阅读此[documentation](https://docs.microsoft.com/zh-cn/xamarin/tools/live-player/),以获取有关Xamarin Live Player及其限制的更多详细信息。 (2认同)

小智 5

要显示 HTML 内容,您可以使用它,它对我来说就像魅力一样,我们不需要使用渲染器来适应内容大小。

<Label BackgroundColor="White" Text="{Binding description}" TextType="Html"/>
Run Code Online (Sandbox Code Playgroud)