如何解决Xamarin.iOS 无法从 WebView Navigating 和 Navigated 事件控制 iOS 活动指示器
我有一个包含 WebView 和 ActivityIndicator 的 ContentPage。有用于 Navigating 和 Navigated 事件的事件处理程序来激活和取消激活 ActivityIndicator。在 iOS 上,会触发 Navigating 事件,但不会始终触发 Navigated 事件。这通常会使 ActivityIndicator 处于永久激活状态。这可以通过导航到 https://www.fairfaxcounty.gov/topics/contact-us 来重现。
有人建议我使用自定义 Web 渲染器来响应 DidFinishNavigation 和 DidFailNavigation 并发送 MessagingCenter 消息以关闭活动指示器。我添加了这个并且它(大部分)有效,但无论出于何种原因(可能是更新到 XF 5 或在幕后更改为 WKWebView),它已停止工作。 DidFinishNavigation 仍然在自定义渲染器中触发,但现在 Navigating 和 Navigated 不再在 WebView 上触发。 DidFailNavigation 永远不会触发,页面呈现完全正确,所以我不认为导航失败是问题所在。如果我移除自定义渲染器,它会返回到 Navigating 事件触发状态,并且 Navigated 仅在某些时候触发。
如果您对此有任何见解,我将不胜感激。
<ContentPage xmlns = "http://xamarin.com/schemas/2014/forms"
xmlns: x = "http://schemas.microsoft.com/winfx/2009/xaml"
xmlns: vm = "clr-namespace:FFXPubXam.viewmodels"
x: Class = "FFXPubXam.Views.WebPage"
x: Name = "root"
Shell.NavBarIsVisible = "false" >
< ContentPage.Content >
< Grid >
< WebView x: Name = "WebViewControl"
Source = "{Binding Url}"
Navigating = "WebViewControl_Navigating"
Navigated = "WebViewControl_Navigated" />
< ActivityIndicator x: Name = "activity"
IsRunning = "False"
IsEnabled = "False"
IsVisible = "False"
HeightRequest = "40"
WidthRequest = "100"
VerticalOptions = "CenterandExpand"
HorizontalOptions = "CenterandExpand"
Color = "{DynamicResource FFX_Blue4}"
BackgroundColor = "Transparent”/>
</ Grid >
</ ContentPage.Content >
</ ContentPage >
[QueryProperty("Url","url")]
[XamlCompilation(XamlCompilationoptions.Compile)]
public partial class WebPage : ContentPage
{
private string baseUrl = string.Empty;
private bool subscribed = false;
private string url;
public string Url
{
set
{
if (value != null)
{
url = Uri.UnescapeDataString(value);
}
}
get
{
return url;
}
}
public WebPage()
{
InitializeComponent();
BindingContext = new WebPageviewmodel();
}
public WebPage(string arg)
{
Url = arg;
InitializeComponent();
BindingContext = new WebPageviewmodel();
}
protected override void OnAppearing()
{
if (baseUrl == string.Empty)
{
if (Url != null)
{
baseUrl = Url;
}
}
if (WebViewControl.source?.ToString() != baseUrl)
{
WebViewControl.source = baseUrl;
}
base.OnAppearing();
Logging.Write(LogType.Info,$"OnAppearing: Url={url}");
if (!subscribed) SubScribe();
ToggleActivityIndicator(true);
}
private void WebViewControl_Navigating(object sender,WebNavigatingEventArgs e)
{
Logging.Write(LogType.Info,$"Navigating: Url={url}");
ToggleActivityIndicator(true);
}
private void WebViewControl_Navigated(object sender,WebNavigatedEventArgs e)
{
Logging.Write(LogType.Info,$"Navigated: Url={url}");
ToggleActivityIndicator(false);
}
private void ToggleActivityIndicator(bool state)
{
Logging.Write(LogType.Info,$"ToggleActivityIndicator: state={state} stack={new StackTrace()}");
activity.IsRunning = state;
activity.IsEnabled = state;
activity.IsVisible = state;
}
private void SubScribe()
{
Logging.Write(LogType.Info,$"Subscribe: call stack={new StackTrace()}");
MessagingCenter.Subscribe<object>(this,"End",(sender) =>
{
ToggleActivityIndicator(false);
});
}
}
[assembly: ExportRenderer(typeof(WebView),typeof(CustomWebVieWrenderer))]
namespace FFXPubXam.iOS.Renderers
{
class MyDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView,WKNavigation navigation)
{
MessagingCenter.Send<object>(this,"End");
Logging.Write(LogType.Info,$"DidFinishNavigation: after Send");
}
public override void DidFailNavigation(WKWebView webView,WKNavigation navigation,NSError error)
{
MessagingCenter.Send<object,string>(this,error.ToString());
}
}
class CustomWebVieWrenderer : WkWebVieWrenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
this.NavigationDelegate = new MyDelegate();
}
}
}
}
解决方法
我测试了您在 XF5 下提供的 URL。即使花了很长时间,WebViewControl_Navigated 还是被触发了。我还测试了网址“https://stackoverflow.com/”,WebViewControl_Navigated 响应很快。
恐怕这个问题的根本原因是“fairfaxcounty”网站。
此外,如果您想在自定义渲染器中调用“ToggleActivityIndicator”,MessagingCenter 不是一个好的选择。您可以通过事件更有效地实现它。
在您的 CustomWebView 类中定义事件:
public class CustomWebView : WebView
{
public delegate void NavigateDel(bool flag);
public event NavigateDel NavigateEvent;
public void CallNavigate(bool flag)
{
NavigateEvent(flag);
}
}
然后在“WebPage”订阅事件:
public WebPage()
{
InitializeComponent();
BindingContext = new WebPageViewModel();
WebViewControl.NavigateEvent += ToggleActivityIndicator;
}
如果您已经创建了自定义渲染器,则无需订阅 Navigating 和 Navigated。要在页面加载时显示指示器,您还需要覆盖“DidStartProvisionalNavigation”。
class MyDelegate : WKNavigationDelegate
{
CustomWebView customView;
public MyDelegate(CustomWebView view)
{
customView = view;
}
public override void DidStartProvisionalNavigation(WKWebView webView,WKNavigation navigation)
{
customView.CallNavigate(true);
}
public override void DidFinishNavigation(WKWebView webView,WKNavigation navigation)
{
customView.CallNavigate(false);
}
public override void DidFailNavigation(WKWebView webView,WKNavigation navigation,NSError error)
{
}
}
class CustomWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
CustomWebView control = (CustomWebView)Element;
this.NavigationDelegate = new MyDelegate(control);
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。