12

I am developing an App using Xamarin.Forms for listing the news from different sources. I use a webView to open the link corresponding to the news. But I want to show the progress while loading the webpage into web view, like the progress bar on Safari App. For this I have used the ProgressBar element like this:

<StackLayout>
            <!-- WebView needs to be given height and width request within layouts to render. -->

            <ProgressBar Progress ="" HorizontalOptions="FillAndExpand" x:Name="progress"/>
            <WebView x:Name="webView" 
                     HeightRequest="1000"
                     WidthRequest="1000"  
                     VerticalOptions= "FillAndExpand" 
                     Navigating="webOnNavigating"
                     Navigated="webOnEndNavigating"/>
        </StackLayout>

and in the code I have used

void webOnNavigating (object sender, WebNavigatingEventArgs e)
        {
            progress.IsVisible = true;

        }

        void webOnEndNavigating (object sender, WebNavigatedEventArgs e)
        {
            progress.IsVisible = false;
        }

But I want to show also the progress of loading the data, not just an indication that is loading and load. I want the user to know that the data are loading. Is there a way to achieve this.

Xhulio
  • 581
  • 7
  • 26

1 Answers1

2

The implementations should be platform specific via custom renders. Luckily this topics has been discussed already for different platforms here on SO.

The Android version based on this thread:

[assembly: ExportRenderer(typeof(WebView), typeof(GenericWebViewRenderer))]
namespace WebViewWithProgressBar.Droid
{
    public class GenericWebViewRenderer : WebViewRenderer
    {
        Context ctx;

        public GenericWebViewRenderer(Context context) : base(context) 
        {
            ctx = context;
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            if (Control == null)
                return;

            var progressBar = new Android.Widget.ProgressBar(ctx, null, Android.Resource.Attribute.ProgressBarStyleHorizontal);
            Control.SetWebChromeClient(new MyWebChromeClient(progressBar));

            Control.AddView(progressBar);
        }

        class MyWebChromeClient : Android.Webkit.WebChromeClient
        {
            Android.Widget.ProgressBar progressBar;

            public MyWebChromeClient(Android.Widget.ProgressBar progressBar)
            {
                this.progressBar = progressBar;
            }

            public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)
            {
                progressBar.SetProgress(newProgress, true);
            }
        }
    }
}

On iOS it is a bit trickier, here is a very simple mock that does it job pretty well:

[assembly: ExportRenderer(typeof(WebView), typeof(GenericWebViewRenderer))]
namespace WebViewWithProgressBar.iOS
{
    public class GenericWebViewRenderer : ViewRenderer<WebView, UIWebView> 
    {
        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged(e);

            if (Control == null)
            {
                var progressBar = new UIProgressView(UIProgressViewStyle.Bar);
                progressBar.TintColor = UIColor.Green;
                progressBar.TrackTintColor = UIColor.Black;
                progressBar.ProgressTintColor = UIColor.Red;

                var webView = new UIWebView(Frame);

                webView.AddSubview(progressBar);

                SetNativeControl(webView);

                Control.Delegate = new MyUIWebViewDelegate(progressBar);

                webView.LoadRequest(new NSUrlRequest(new NSUrl("https://google.com")));
            }
        }

        class MyUIWebViewDelegate : UIWebViewDelegate
        {
            UIProgressView progressBar { get; }

            public MyUIWebViewDelegate(UIProgressView progressBar)
            {
                this.progressBar = progressBar;
            }

            public override void LoadStarted(UIWebView webView)
            {
                progressBar.SetProgress(0.1f, false);
            }

            public override void LoadingFinished(UIWebView webView)
            {
                progressBar.SetProgress(1.0f, true);
            }

            public override void LoadFailed(UIWebView webView, NSError error)
            {
                // TODO:
            }
        }
    }
}

For more details please check here.

P.S.: This code examples are available on github.

EvZ
  • 11,889
  • 4
  • 38
  • 76
  • Doesn't this create a new progressbar instead of using the one that's already in the stacklayout? – Denny Aug 31 '18 at 08:58
  • Which ‘StackLayout’? WebViews does not have any progress indicators by default. – EvZ Aug 31 '18 at 09:31
  • The StackLayout that the OP posted, it has a ProgressBar and a Webview in it – Denny Aug 31 '18 at 09:39
  • My suggestion is based on a pure ‘WebView’ control with extending it’s default renderers. It does not require to create any custom controls (unless required), so it has nothing to do with the ‘StackLayout’ that was initially posted in the question. – EvZ Aug 31 '18 at 09:45
  • Would it be possible for a custom webviewrenderer to update the progressbar that's already in the stacklayout? – Denny Aug 31 '18 at 09:51
  • 1
    Yes, but since this task is not trivial it might be easier to add and update progress bar from the renderer as suggested above. – EvZ Aug 31 '18 at 09:56