【问题标题】:Xamarin Forms Webview - Scroll eventXamarin Forms Webview - 滚动事件
【发布时间】:2018-12-01 17:11:27
【问题描述】:

我需要知道用户何时结束在显示协议的 web 视图上的滚动,以便仅在用户阅读此内容时显示“接受”。

这是我的网络视图 (xaml):

  <WebView x:Name="webView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<WebView.Source>
  <HtmlWebViewSource Html="{Binding Content}" />
</WebView.Source>

我该怎么做(.cs 方面)?.. 最佳做法是什么?

Xamarin 表单 - 目标:iOS 和 Android

感谢您的帮助;)

编辑(iOS/Android 工作解决方案): 这是我在 webview(JS 事件)中监听滚动的实现:

自定义 WebView 渲染器:

namespace xxx.Views.Common.Controls
{
public class WebViewer : WebView
{
    public static BindableProperty EvaluateJavascriptProperty =
        BindableProperty.Create(nameof(EvaluateJavascript), typeof(Func<string, Task<string>>), typeof(WebViewer),
                                null, BindingMode.OneWayToSource);

    public static BindableProperty RefreshProperty =
        BindableProperty.Create(nameof(Refresh), typeof(Action), typeof(WebViewer), null,
                                BindingMode.OneWayToSource);

    public static BindableProperty GoBackProperty =
        BindableProperty.Create(nameof(GoBack), typeof(Action), typeof(WebViewer), null,
                                BindingMode.OneWayToSource);

    public static BindableProperty CanGoBackFunctionProperty =
        BindableProperty.Create(nameof(CanGoBackFunction), typeof(Func<bool>), typeof(WebViewer), null,
                                BindingMode.OneWayToSource);

    public static BindableProperty GoBackNavigationProperty =
        BindableProperty.Create(nameof(GoBackNavigation), typeof(Action), typeof(WebViewer), null,
                                BindingMode.OneWay);

    public Func<string, Task<string>> EvaluateJavascript
    {
        get { return (Func<string, Task<string>>) this.GetValue(EvaluateJavascriptProperty); }
        set { this.SetValue(EvaluateJavascriptProperty, value); }
    }

    public Action Refresh
    {
        get { return (Action) this.GetValue(RefreshProperty); }
        set { this.SetValue(RefreshProperty, value); }
    }

    public Func<bool> CanGoBackFunction
    {
        get { return (Func<bool>) this.GetValue(CanGoBackFunctionProperty); }
        set { this.SetValue(CanGoBackFunctionProperty, value); }
    }

    public Action GoBackNavigation
    {
        get { return (Action) this.GetValue(GoBackNavigationProperty); }
        set { this.SetValue(GoBackNavigationProperty, value); }
    }
}
}

Android 渲染器:

[assembly: ExportRenderer(typeof(WebViewer), typeof(WebViewRender))]

namespace xxx.Droid.Renderers
{
public class WebViewRender : WebViewRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
    {
        base.OnElementChanged(e);

        var oldWebView = e.OldElement as WebViewer;
        if (oldWebView != null)
        {
            oldWebView.EvaluateJavascript = null;
        }

        var newWebView = e.NewElement as WebViewer;
        if (newWebView != null)
        {
            newWebView.EvaluateJavascript = async js =>
            {
                ManualResetEvent reset = new ManualResetEvent(false);
                var response = "";
                Device.BeginInvokeOnMainThread(() =>
                {
                    System.Diagnostics.Debug.WriteLine("Javascript Send: " + js);
                    this.Control?.EvaluateJavascript(js, new JavascriptCallback(r =>
                    {
                        response = r;
                        reset.Set();
                    }));
                });
                await Task.Run(() => { reset.WaitOne(); });
                if (response == "null")
                {
                    response = string.Empty;
                }

                return response;
            };
        }

        if (this.Control != null && e.NewElement != null)
        {
            this.SetupControl();
        }
    }

    /// <summary>
    ///     Sets up various settings for the Android WebView
    /// </summary>
    private void SetupControl()
    {
        // Ensure common functionality is enabled
        this.Control.Settings.DomStorageEnabled = true;
        this.Control.Settings.JavaScriptEnabled = true;

        // Must remove minimum font size otherwise SAP PDF's go massive
        this.Control.Settings.MinimumFontSize = 0;

        // Because Android 4.4 and below doesn't respect ViewPort in HTML
        if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
        {
            this.Control.Settings.UseWideViewPort = true;
        }
    }
}

internal class JavascriptCallback : Java.Lang.Object, IValueCallback
{
    private readonly Action<string> _callback;

    public JavascriptCallback(Action<string> callback)
    {
        this._callback = callback;
    }

    public void OnReceiveValue(Java.Lang.Object value)
    {
        System.Diagnostics.Debug.WriteLine("Javascript Return: " + Convert.ToString(value));
        this._callback?.Invoke(Convert.ToString(value));
    }
}

public class WebViewChromeClient : WebChromeClient
{
    readonly Action<IValueCallback, Java.Lang.String, Java.Lang.String> callback;

    public WebViewChromeClient(Action<IValueCallback, Java.Lang.String, Java.Lang.String> callback)
    {
        this.callback = callback;
    }

    //For Android 4.1+
    [Java.Interop.Export]
    public void openFileChooser(IValueCallback uploadMsg, Java.Lang.String acceptType, Java.Lang.String capture)
    {
        this.callback(uploadMsg, acceptType, capture);
    }

    // For Android 5.0+
    public override bool OnShowFileChooser(WebView webView, IValueCallback filePathCallback,
                                           FileChooserParams fileChooserParams)
    {
        return base.OnShowFileChooser(webView, filePathCallback, fileChooserParams);
    }
}
}

iOS 渲染器:

[assembly: ExportRenderer(typeof(WebViewer), typeof(WebViewRender))]

namespace xxx.iOS
{
public class WebViewRender : WebViewRenderer
{
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);

        //if (this.NativeView != null && e.NewElement != null)
        //{
        //    this.InitializeCommands((WebViewer) e.NewElement);
        //}

        var webView = e.NewElement as WebViewer;
        if (webView != null)
        {
            webView.EvaluateJavascript = js => { return Task.FromResult(this.EvaluateJavascript(js)); };
        }
    }

    private void InitializeCommands(WebViewer element)
    {
        var ctl = (UIWebView) this.NativeView;

        ctl.ScalesPageToFit = true;
    }
}
}

xaml 显示:

            <pages:xxxContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:pages="clr-namespace:xxx.Views"
        xmlns:controls="clr-namespace:xxx.Views.Common.Controls;assembly=xxx.View"
        x:Class="xxx.Views.AboutPage">
  <pages:xxxInfoContentPage.PageView>
    <StackLayout HorizontalOptions="FillAndExpand"
                 VerticalOptions="FillAndExpand">
        <controls:WebViewer x:Name="webView" EvaluateJavascript="{Binding EvaluateJavascript}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
            <WebView.Source>
                <HtmlWebViewSource Html="{Binding Content}" />
            </WebView.Source>
        </controls:WebViewer>
    </StackLayout>
  </pages:DriversInfoContentPage.PageView>
</pages:DriversInfoContentPage>

JS inside webview(到达底部时重定向):

<script type="text/javascript">
function init() {
    window.onscroll = function(ev) {
        if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
            window.location.hash = "bottom";
            location.reload();
        }
    };
}
</script>

<body onload="init()">
    <!-- Scrolled content-->
</body>

捕获和取消导航事件 xaml.xs 端:

public AboutPage()
    {
        this.webView.Navigating += this.NavigatingEvent;
    }   

private void NavigatingEvent(object sender, WebNavigatingEventArgs e)
    {
        if (e.Url.Contains("bottom") || e.Url.Contains("about:blank"))
        {
            e.Cancel = true;

            // ACTION WHEN BOTTOM IS REACHED HERE
        }
    }

【问题讨论】:

  • 我试过了,没有成功,我无法正确覆盖“onscroll”事件
  • 我为此做了一个 cronroller,你还需要它吗?

标签: xamarin xamarin.forms


【解决方案1】:

我建议让您的 C# 访问 javascript。

看我的教程:

https://www.youtube.com/watch?v=_0a7NzkNl-Q

【讨论】:

    猜你喜欢
    • 2018-02-19
    • 2018-04-05
    • 2021-10-10
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    • 2018-07-22
    • 2021-09-19
    • 2021-05-28
    相关资源
    最近更新 更多