Sunday, September 9, 2018

How to update progressbar from customwebview renderer in xamarin forms for android?

Leave a Comment

I'm currently developing an app in Xamarin Forms with an Android background so I wanted to create an Android app first and an iOS app later.

I'm new to Xamarin Forms and I'm struggling on how to update a ProgressBar from a WebView using a custom renderer for the WebView.

In Android, you can do something like this, with the ProgressBar and WebView that are in the main_layout.xml

public class MainActivity extends Activity {      private ProgressBar progressBar;     private WebView webView;          @Override     protected void onCreate(Bundle savedInstanceState) {              super.onCreate(savedInstanceState);         setContentView(R.layout.main_layout);          progressBar = (ProgressBar) findViewById(R.id.progress);         webView = (AdvancedWebView) findViewById(R.id.webView);         // webview initialisation         webView.setWebChromeClient(new WebChromeClient(){             @Override             public void onProgressChanged(WebView view, int newProgress) {                 // update progressbar progress                 progressBar.setProgress(newProgress);            }        });         webView.setWebViewClient(new WebViewClient(this) {             @Override             public void onPageFinished(WebView view, String url) {                 // hide progressbar when it's done                 progressBar.setVisibility(View.GONE);             }         });     } } 

In Xamarin Forms I have this layout in MainPage.xaml in the shared project

<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="MainPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" NavigationPage.HasNavigationBar="False">  <Grid>     <Grid.RowDefinitions>         <RowDefinition Height="*" />         <RowDefinition Height="*" />         <RowDefinition Height="*" />         <RowDefinition Height="*" />     </Grid.RowDefinitions>      <ProgressBar         x:Name="progress"         Grid.Row="3"         HorizontalOptions="FillAndExpand"         Progress="0"         VerticalOptions="Center" />      <WebView         x:Name="webview"         Grid.Row="0"         Grid.RowSpan="4"         Grid.Column="0"         HorizontalOptions="FillAndExpand"         IsVisible="False"         Source="https://google.com"         VerticalOptions="FillAndExpand" />  </Grid> 

public partial class App : Application {     public App ()     {         InitializeComponent();          MainPage = new MainPage();      } } 

And this custom WebView render for android in the android project

[assembly: ExportRenderer(typeof(WebView), typeof(CustomWebviewRenderer))] namespace MyApp.Droid {     public class CustomWebviewRenderer: WebViewRenderer     {         private readonly Context context;          public CustomWebviewRenderer(Context context) : base(context)         {             this.context = context;         }          protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)         {             base.OnElementChanged(e);             var formsWebView = e.NewElement as Xamarin.Forms.WebView;              if (formsWebView != null)             {                 var webView = Control as Android.Webkit.WebView;                 webView.SetWebViewClient(new CustomWebViewClient());                  webView.SetWebChromeClient(new CustomWebChromeClient());                      webView.Settings.LoadWithOverviewMode = true;                 webView.Settings.UseWideViewPort = true;                 SetNativeControl(webView);             }         }          private class ScoritoWebChromeClient : WebChromeClient         {             public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)             {                 // how to update progressbar progress?                 base.OnProgressChanged(view, newProgress);                            }         }          private class CustomWebViewClient : WebViewClient         {             public override void OnPageFinished(Android.Webkit.WebView view, string url)             {                 // how to hide progressbar?                 base.OnPageFinished(view, url);             }              public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon)             {                 base.OnPageStarted(view, url, favicon);             }              public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)             {                 return base.ShouldOverrideUrlLoading(view, request);             }         }     } } 

How can I update the ProgressBar that I have in my MainPage.xaml from the OnPageFinished in the CustomWebviewRenderer class to show the webpage has finished loading? Should I use the MainActivity.cs in the Android project?

Can someone point me in the right direction on how to solve this?

1 Answers

Answers 1

You don't need custom renderers for what you are doing first and foremost.

Why don't you use the Navigating & Navigated Binding's in your Xamarin forms Webview?

<WebView x:Name="Webview"                          Navigating="OnNavigating"            Navigated="OnNavigated"            VerticalOptions="FillAndExpand"/>   

And then do this in your xaml.cs:

 protected async override void OnAppearing()       {           base.OnAppearing();            await progress.ProgressTo(0.9, 900, Easing.SpringIn);       }     private void OnNavigated(object sender, Xamarin.Forms.WebNavigatedEventArgs e)     {       progress.IsVisible = false;       }      private void OnNavigating(object sender, Xamarin.Forms.WebNavigatingEventArgs e)     {        progress.IsVisible = true;     } 

And this should be enough

But if you still insist to use your renderer what you can do is update the progress bar using the element property and get a callback or change a property something like below:

[assembly: ExportRenderer(typeof(WebView), typeof(CustomWebviewRenderer))]  namespace MyApp.Droid { public class CustomWebviewRenderer: WebViewRenderer {     private readonly Context context;    private MainPage MainPage     {         get         {             var mainPage = Element as MainPage;             return mainPage == null                 ? null                 : mainPage;         }     }     public CustomWebviewRenderer(Context context) : base(context)     {         this.context = context;     }      protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)     {         base.OnElementChanged(e);         var formsWebView = e.NewElement as Xamarin.Forms.WebView;          if (formsWebView != null)         {             var webView = Control as Android.Webkit.WebView;             webView.SetWebViewClient(new CustomWebViewClient());              webView.SetWebChromeClient(new CustomWebChromeClient());                  webView.Settings.LoadWithOverviewMode = true;             webView.Settings.UseWideViewPort = true;             SetNativeControl(webView);         }     }      private class ScoritoWebChromeClient : WebChromeClient     {         public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)         {             // how to update progressbar progress?             base.OnProgressChanged(view, newProgress);                        }     }      private class CustomWebViewClient : WebViewClient     {         public override void OnPageFinished(Android.Webkit.WebView view, string url)         {             // how to hide progressbar?             MainPage.yourCallbackFunc();             base.OnPageFinished(view, url);         }          public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon)         {             base.OnPageStarted(view, url, favicon);         }          public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)         {             return base.ShouldOverrideUrlLoading(view, request);         }     }   } } 

And get the callback in that xamarin forms page:

  public partial class MainPage: ContentPage  {      public MainPage()      {          InitializeComponent();       }      public void yourCallbackFunc()      {       .       . // Do some functionality       .       }  } 

In case it doesn't work or you have queries revert!

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment