Xamarin Forms WebView Navigated event not firing consistently on iOS

Viewed 1255

I have a Xamarin Forms ContentPage that has a WebView and an ActivityIndicator. I've wired up event handlers to to the WebView Navigating and Navigated events to activate and de-activate the ActivityIndicator. This all works great on Android. On iOS, the Navigating event fires multiple times as the page loads, but the Navigated event does not fire consistently with it. This often leaves the ActivityIndicator in a perpetually activated state. Has anyone found a fix or workaround that doesn't involve a custom WebView render or is a custom renderer the only way to go? If a custom renderer is required, does anyone have an example that works for this purpose?

Updated: Added the code here as requested.

<?xml version="1.0" encoding="utf-8" ?>
<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>

using FFXPubXam.Helpers;
using FFXPubXam.ViewModels;
using System;
using Xamarin.Forms;

namespace FFXPubXam.Views
{
    public partial class WebPage : ContentPage
    {
        public WebPage(string arg)
        {
            InitializeComponent();
            BindingContext = new WebPageViewModel(arg);
        }

        protected override void OnAppearing()
        {
            ToggleActivityIndicator(true);

            base.OnAppearing();
        }

        private void WebViewControl_Navigating(object sender, WebNavigatingEventArgs e)
        {
            ToggleActivityIndicator(true);
        }

        private void WebViewControl_Navigated(object sender, WebNavigatedEventArgs e)
        {
            ToggleActivityIndicator(false);
        }

        private void ToggleActivityIndicator(bool state)
        {
            activity.IsRunning = state;
            activity.IsEnabled = state;
            activity.IsVisible = state;
        }
    }
}
2 Answers

I've found that the target attribute of HTML links displayed in Xamarin WebViews can stop the Navigating event from firing if set to _blank. A simple if hacky fix is just to remove them in code like this:

var htmlSource = new HtmlWebViewSource();
// remove target="_blank" to make Navigating event fire:
htmlSource.Html = htmlString.Replace("target=\"_blank\"", "").Replace("target='_blank'", "");

webView.Source = htmlSource;

Or else you could remove them from your HTML source.

I was not able to get either Navigated or Navigating to fire on Android, haven't tested on iOS yet but this maybe because I'm loading a local HTML file so my circumstance is a little bit different...Either way this workaround may help for this general problem because it DOES still fire Navigating multiple times but before I wasn't getting either.

I needed to set WebView.Source, WebView.Navigating and WebView.Navigated in the code-behind NOT in the Xaml like this:

public WebPage(string arg) {
    InitializeComponent();
    BindingContext = new WebPageViewModel(arg);
    WebViewControl.Source = (BindingContext as WebPageViewModel).Url;

    WebViewControl.Navigating += WebViewControl_Navigating;
    WebViewControl.Navigated += ContentEditorWebView_Navigated;
}

I am not sure the reason why this happens but I think it is due to WebView being non-native and the rendering only occurs when the device specific control is created.

Related