Xamarin.iOS可以’;t从WebView导航和导航事件控制iOS活动指示器
我有一个ContentPage,它有一个WebView和一个ActivityIndicator。有用于导航和导航事件的事件处理程序来激活和取消激活ActivityIndicator。在iOS上,导航事件会激发,但导航事件不会持续激发。这通常会使ActivityIndicator处于永久激活状态。通过导航到,可以复制此内容 有人建议我使用自定义web渲染器响应DidFinishNavigation和DidFailNavigation,并发送MessagingCenter消息以关闭活动指示器。我添加了这个,它(大部分)起了作用,但无论出于什么原因(可能是XF 5的更新或WKWebView的更改),它都停止了工作。DidFinishNavigation仍在自定义渲染器中启动,但现在Navigation和Navigated从未在WebView中启动。DidFailNavigation从不触发,页面呈现完全正确,因此我不认为导航失败是问题所在。如果删除自定义渲染器,它将返回到导航事件触发,并且导航仅在某些时间触发 我将非常感谢任何关于这方面的见解Xamarin.iOS可以’;t从WebView导航和导航事件控制iOS活动指示器,webview,xamarin.ios,navigation,Webview,Xamarin.ios,Navigation,我有一个ContentPage,它有一个WebView和一个ActivityIndicator。有用于导航和导航事件的事件处理程序来激活和取消激活ActivityIndicator。在iOS上,导航事件会激发,但导航事件不会持续激发。这通常会使ActivityIndicator处于永久激活状态。通过导航到,可以复制此内容 有人建议我使用自定义web渲染器响应DidFinishNavigation和DidFailNavigation,并发送MessagingCenter消息以关闭活动指示器。我添加
<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, "End", error.ToString());
}
}
class CustomWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
this.NavigationDelegate = new MyDelegate();
}
}
}
}
[查询属性(“Url”、“Url”)]
[XamlCompilation(XamlCompilationOptions.Compile)]
公共部分类网页:ContentPage
{
私有字符串baseUrl=string.Empty;
private bool subscribed=false;
私有字符串url;
公共字符串Url
{
设置
{
if(值!=null)
{
url=Uri.UnescapeDataString(值);
}
}
得到
{
返回url;
}
}
公共网页()
{
初始化组件();
BindingContext=新的WebPageViewModel();
}
公共网页(字符串arg)
{
Url=arg;
初始化组件();
BindingContext=新的WebPageViewModel();
}
出现时受保护的覆盖无效()
{
if(baseUrl==string.Empty)
{
如果(Url!=null)
{
baseUrl=Url;
}
}
if(WebViewControl.Source?.ToString()!=baseUrl)
{
WebViewControl.Source=baseUrl;
}
base.OnAppearing();
Write(LogType.Info,$”OnAppearing:Url={Url});
如果(!subscribed)SubScribe();
ToggleActivityIndicator(真);
}
私有void WebViewControl_导航(对象发送方,WebNavigatingEventArgs e)
{
Write(LogType.Info,$“导航:Url={Url}”);
ToggleActivityIndicator(真);
}
私有void WebViewControl_已导航(对象发送方,WebNavigatedEventArgs e)
{
Write(LogType.Info,$“Navigated:Url={Url}”);
ToggleActivityIndicator(假);
}
私有无效TogleActivityIndicator(布尔状态)
{
Write(LogType.Info,$“ToggleActivityIndicator:state={state}stack={new StackTrace()}”);
activity.IsRunning=状态;
activity.IsEnabled=状态;
activity.IsVisible=状态;
}
私有无效订阅()
{
Write(LogType.Info,$“Subscribe:callstack={newstacktrace()}”);
MessagingCenter.Subscribe(此“结束”,(发件人)=>
{
ToggleActivityIndicator(假);
});
}
}
[程序集:ExportRenderer(typeof(WebView)、typeof(CustomWebViewRenderer))]
命名空间FFXPubXam.iOS.Renderers
{
类MyDelegate:WKNavigationDelegate
{
公共覆盖无效DidFinishNavigation(WKWebView、WKNavigation导航)
{
发送(此“结束”);
Logging.Write(LogType.Info,$“didfishnavigation:after Send”);
}
公共覆盖无效导航(WKWebView webView、WKNavigation导航、N错误)
{
Send(这个“End”,error.ToString());
}
}
类CustomWebViewRenderer:WkWebViewRenderer
{
受保护的覆盖无效OnElementChanged(VisualElementChangedEventArgs e)
{
基础。一个要素发生变化(e);
if(例如NewElement!=null)
{
this.NavigationDelegate=新的MyDelegate();
}
}
}
}
我测试了您在XF5下提供的URL。尽管花费了很长时间,但还是触发了WebViewControl\u导航。我还测试了URL“https://stackoverflow.com/“,WebViewControl_导航迅速响应
恐怕这个问题的根本原因是“费尔法克斯县”网站
此外,如果要在自定义渲染器中调用“ToggleActivityIndicator”,MessagingCenter不是一个好选择。您可以通过事件更有效地实现它
在CustomWebView类中定义事件:
public class CustomWebView : WebView
{
public delegate void NavigateDel(bool flag);
public event NavigateDel NavigateEvent;
public void CallNavigate(bool flag)
{
NavigateEvent(flag);
}
}
然后在“网页”中订阅活动:
如果已创建自定义呈现程序,则无需订阅导航和导航。要在加载页面时显示指示器,还需要覆盖“DidStartProvisi”
public WebPage()
{
InitializeComponent();
BindingContext = new WebPageViewModel();
WebViewControl.NavigateEvent += ToggleActivityIndicator;
}
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);
}
}
}