This is an automated email from the ASF dual-hosted git repository.

GitToTheHub pushed a commit to branch pr-ios-switch-spinner-to-progress-bar
in repository 
https://gitbox.apache.org/repos/asf/cordova-plugin-inappbrowser.git

commit b04c1a56b8a78b50315b6c86ca62c076737aec77
Author: Manuel Beck <[email protected]>
AuthorDate: Thu Aug 13 20:13:29 2026 +0200

    feat(ios): switch from spinner to progress bar
    
    - PR #1169 implemented a progress bar for Android. Today it's more common 
to use a progress bar instead of a spinner to indicate loading of web page as 
it is the default for the Safari app. This aligns it with Android and use the 
same option `hideloadingindicator` as for Android. The old option `hidespinner` 
is still supported and will be an alias for `hideloadingindicator`.
---
 README.md                        |  5 ++--
 src/ios/CDVInAppBrowserOptions.h |  2 +-
 src/ios/CDVInAppBrowserOptions.m |  8 ++++-
 src/ios/CDVWKInAppBrowser.h      |  2 +-
 src/ios/CDVWKInAppBrowser.m      | 64 +++++++++++++++++++++++++++-------------
 5 files changed, 54 insertions(+), 27 deletions(-)

diff --git a/README.md b/README.md
index 9f0bd3f5..f40671f9 100644
--- a/README.md
+++ b/README.md
@@ -158,9 +158,8 @@ instance, or the system browser.
     - __presentationstyle__:  Set to `pagesheet`, `formsheet` or `fullscreen` 
to set the [presentation 
style](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle)
 (defaults to `fullscreen`).
     - __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or 
`coververtical` to set the [transition 
style](https://developer.apple.com/documentation/uikit/uimodaltransitionstyle) 
(defaults to `coververtical`).
     - __toolbarposition__: Set to `top` or `bottom` (default is `bottom`). 
Causes the toolbar to be at the top or bottom of the window.
-    - __hidespinner__: Set to `yes` or `no` to change the visibility of the 
loading indicator (defaults to `no`).
-
-
+    - __hideloadingindicator__: Set to `yes` to hide the loading progress bar. 
Set to `no` or omit it to show the bar while pages load (default is `no`).
+    - __hidespinner__: Deprecated alias for `hideloadingindicator`.
 ### Supported Platforms
 
 - Android
diff --git a/src/ios/CDVInAppBrowserOptions.h b/src/ios/CDVInAppBrowserOptions.h
index 83df264c..743c4ffe 100644
--- a/src/ios/CDVInAppBrowserOptions.h
+++ b/src/ios/CDVInAppBrowserOptions.h
@@ -34,7 +34,7 @@
 @property (nonatomic, assign) BOOL cleardata;
 @property (nonatomic, assign) BOOL clearcache;
 @property (nonatomic, assign) BOOL clearsessioncache;
-@property (nonatomic, assign) BOOL hidespinner;
+@property (nonatomic, assign) BOOL hideloadingindicator;
 
 @property (nonatomic, copy) NSString *presentationstyle;
 @property (nonatomic, copy) NSString *transitionstyle;
diff --git a/src/ios/CDVInAppBrowserOptions.m b/src/ios/CDVInAppBrowserOptions.m
index cc77788a..332f052d 100644
--- a/src/ios/CDVInAppBrowserOptions.m
+++ b/src/ios/CDVInAppBrowserOptions.m
@@ -32,7 +32,7 @@
         self.cleardata = NO;
         self.clearcache = NO;
         self.clearsessioncache = NO;
-        self.hidespinner = NO;
+        self.hideloadingindicator = NO;
 
         self.enableviewportscale = NO;
         self.mediaplaybackrequiresuseraction = NO;
@@ -66,6 +66,12 @@
             NSString *value = [keyvalue objectAtIndex:1];
             NSString *value_lc = [value lowercaseString];
 
+            // In version 7.0.1 this was renamed to "hideloadingindicator"
+            // but we still support the old name for backwards compatibility.
+            if ([key isEqualToString:@"hidespinner"]) {
+                key = @"hideloadingindicator";
+            }
+
             BOOL isBoolean = [value_lc isEqualToString:@"yes"] || [value_lc 
isEqualToString:@"no"];
             NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] 
init];
             [numberFormatter setAllowsFloats:YES];
diff --git a/src/ios/CDVWKInAppBrowser.h b/src/ios/CDVWKInAppBrowser.h
index a5ba51b6..5b15e638 100644
--- a/src/ios/CDVWKInAppBrowser.h
+++ b/src/ios/CDVWKInAppBrowser.h
@@ -72,7 +72,7 @@ typedef NSDictionary CDVSettingsDictionary;
 @property (nonatomic, strong) IBOutlet UILabel *addressLabel;
 @property (nonatomic, strong) IBOutlet UIBarButtonItem *backButton;
 @property (nonatomic, strong) IBOutlet UIBarButtonItem *forwardButton;
-@property (nonatomic, strong) IBOutlet UIActivityIndicatorView *spinner;
+@property (nonatomic, strong) IBOutlet UIProgressView *progressView;
 @property (nonatomic, strong) IBOutlet UIView *toolbarBackground;
 @property (nonatomic, strong) IBOutlet UIToolbar *toolbar;
 @property (nonatomic, strong) IBOutlet CDVWKInAppBrowserUIDelegate 
*webViewUIDelegate;
diff --git a/src/ios/CDVWKInAppBrowser.m b/src/ios/CDVWKInAppBrowser.m
index 7638af60..01907266 100644
--- a/src/ios/CDVWKInAppBrowser.m
+++ b/src/ios/CDVWKInAppBrowser.m
@@ -736,6 +736,7 @@ static UIBarButtonSystemItem 
CDVWKInAppBrowserCloseButtonSystemItem(void)
     [self.inAppBrowserViewController.webView removeFromSuperview];
     [self.inAppBrowserViewController.webView setUIDelegate:nil];
     [self.inAppBrowserViewController.webView setNavigationDelegate:nil];
+    [self.inAppBrowserViewController.webView 
removeObserver:self.inAppBrowserViewController forKeyPath:@"estimatedProgress"];
     self.inAppBrowserViewController.webView = nil;
 
     // Set navigationDelegate to nil to ensure no callbacks are received from 
it.
@@ -759,6 +760,11 @@ static UIBarButtonSystemItem 
CDVWKInAppBrowserCloseButtonSystemItem(void)
 CGFloat lastReducedStatusBarHeight = 0.0;
 BOOL isExiting = NO;
 
+- (void)dealloc
+{
+    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
+}
+
 - (id)initWithBrowserOptions:(CDVInAppBrowserOptions *)browserOptions 
andSettings:(CDVSettingsDictionary *)settings
 {
     self = [super init];
@@ -838,7 +844,7 @@ BOOL isExiting = NO;
 #endif
 
     [self.view addSubview:self.webView];
-    // The WebView should be behind the other elements like toolbar, address 
label, spinner
+    // The WebView should be behind the other elements like toolbar, address 
label, and progress bar
     // Since the WebView is added first, this is already the case.
     // sendSubviewToBack is normally not necessary.
     [self.view sendSubviewToBack:self.webView];
@@ -901,19 +907,14 @@ BOOL isExiting = NO;
     self.addressLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [self.addressBackgroundView addSubview:self.addressLabel];
     
-    self.spinner = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
-    self.spinner.clearsContextBeforeDrawing = NO;
-    self.spinner.clipsToBounds = NO;
-    self.spinner.contentMode = UIViewContentModeScaleToFill;
-    self.spinner.hidden = NO;
-    self.spinner.hidesWhenStopped = YES;
-    self.spinner.multipleTouchEnabled = NO;
-    self.spinner.opaque = NO;
-    self.spinner.userInteractionEnabled = NO;
-    [self.spinner stopAnimating];
-    [self.view addSubview:self.spinner];
+    self.progressView = [[UIProgressView alloc] 
initWithProgressViewStyle:UIProgressViewStyleDefault];
+    self.progressView.hidden = YES;
+    self.progressView.userInteractionEnabled = NO;
+    [self.view addSubview:self.progressView];
     // We add our own constraints, they should not be determined from the 
frame.
-    self.spinner.translatesAutoresizingMaskIntoConstraints = NO;
+    self.progressView.translatesAutoresizingMaskIntoConstraints = NO;
+    // Observe WebKit's estimated load progress to update the native progress 
indicator.
+    [self.webView addObserver:self forKeyPath:@"estimatedProgress" 
options:NSKeyValueObservingOptionNew context:nil];
 
     // NOTE: On iOS 26 using `UIBarButtonItem initWithBarButtonSystemItem:` 
gives constraint warnings,
     // which is a known UIKit bug.
@@ -1027,9 +1028,12 @@ BOOL isExiting = NO;
         [self.addressLabel.trailingAnchor 
constraintEqualToAnchor:self.addressBackgroundView.layoutMarginsGuide.trailingAnchor]
     ]];
 
-    // Center spinner in WebView
-    [self.spinner.centerXAnchor 
constraintEqualToAnchor:self.webView.centerXAnchor].active = YES;
-    [self.spinner.centerYAnchor 
constraintEqualToAnchor:self.webView.centerYAnchor].active = YES;
+    // Position the progress bar at the top edge of the WebView.
+    [NSLayoutConstraint activateConstraints:@[
+        [self.progressView.topAnchor 
constraintEqualToAnchor:self.webView.topAnchor],
+        [self.progressView.leadingAnchor 
constraintEqualToAnchor:self.webView.leadingAnchor],
+        [self.progressView.trailingAnchor 
constraintEqualToAnchor:self.webView.trailingAnchor]
+    ]];
 
     // Define vertical constraints, in order from top to bottom
     // Don't extend behind the status bar like also the Safari app does and 
restraint
@@ -1219,6 +1223,21 @@ BOOL isExiting = NO;
     }
 }
 
+/**
+ * Mirrors WKWebView's estimated loading progress in the native progress 
indicator.
+ */
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
+{
+    if (object == self.webView && [keyPath 
isEqualToString:@"estimatedProgress"]) {
+        if (!_browserOptions.hideloadingindicator) {
+            self.progressView.progress = self.webView.estimatedProgress;
+        }
+        return;
+    }
+
+    [super observeValueForKeyPath:keyPath ofObject:object change:change 
context:context];
+}
+
 - (void)goBack:(id)sender
 {
     [self.webView goBack];
@@ -1246,12 +1265,15 @@ BOOL isExiting = NO;
 - (void)webView:(WKWebView *)theWebView 
didStartProvisionalNavigation:(WKNavigation *)navigation
 {
     NSLog(@"didStartProvisionalNavigation");
-    // Loading URL, start spinner, update back/forward
+    // Loading URL, show progress bar, update back/forward
     self.addressLabel.text = NSLocalizedString(@"Loading...", nil);
     self.backButton.enabled = theWebView.canGoBack;
     self.forwardButton.enabled = theWebView.canGoForward;
 
-    if (!_browserOptions.hidespinner) [self.spinner startAnimating];
+    if (!_browserOptions.hideloadingindicator) {
+        self.progressView.progress = 0.0;
+        self.progressView.hidden = NO;
+    }
     return [self.navigationDelegate didStartProvisionalNavigation:theWebView];
 }
 
@@ -1274,12 +1296,12 @@ decisionHandler:(void 
(^)(WKNavigationActionPolicy))decisionHandler
 - (void)webView:(WKWebView *)theWebView didFinishNavigation:(WKNavigation 
*)navigation
 {
     NSLog(@"didFinishNavigation");
-    // Update URL, stop spinner, update back/forward
+    // Update URL, hide progress bar, update back/forward
     self.addressLabel.text = self.currentURL.absoluteString;
     self.backButton.enabled = theWebView.canGoBack;
     self.forwardButton.enabled = theWebView.canGoForward;
     theWebView.scrollView.contentInset = UIEdgeInsetsZero;
-    [self.spinner stopAnimating];
+    self.progressView.hidden = YES;
     [self.navigationDelegate didFinishNavigation:theWebView];
 }
 
@@ -1287,7 +1309,7 @@ decisionHandler:(void 
(^)(WKNavigationActionPolicy))decisionHandler
 {
     self.backButton.enabled = theWebView.canGoBack;
     self.forwardButton.enabled = theWebView.canGoForward;
-    [self.spinner stopAnimating];
+    self.progressView.hidden = YES;
 
     BOOL isBeforeloadEnabled = self.navigationDelegate != nil && 
[self.navigationDelegate isBeforeloadEnabled];
     


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to