You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ma...@apache.org on 2026/03/04 08:27:26 UTC

(cordova-plugin-inappbrowser) 01/02: fix(ios): Add custom toolbar background

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

manuelbeck pushed a commit to branch pr-ios-overlay-toolbar-address-label-on-webview
in repository https://gitbox.apache.org/repos/asf/cordova-plugin-inappbrowser.git

commit 38deebba244d87c6edb58a2e8e8e0d040de7f04e
Author: Manuel Beck <ma...@outlook.de>
AuthorDate: Wed Mar 4 09:26:06 2026 +0100

    fix(ios): Add custom toolbar background
    
    - On iOS 26 the background color cannot be set anymore. To make this configurable, a custom background is added, which is also used on iOS 18 and older
---
 src/ios/CDVWKInAppBrowser.h |   1 +
 src/ios/CDVWKInAppBrowser.m | 200 ++++++++++++++++++++++++--------------------
 2 files changed, 111 insertions(+), 90 deletions(-)

diff --git a/src/ios/CDVWKInAppBrowser.h b/src/ios/CDVWKInAppBrowser.h
index 9867ac0..12fcb19 100644
--- a/src/ios/CDVWKInAppBrowser.h
+++ b/src/ios/CDVWKInAppBrowser.h
@@ -72,6 +72,7 @@ typedef NSDictionary CDVSettingsDictionary;
 @property (nonatomic, strong) IBOutlet UIBarButtonItem *backButton;
 @property (nonatomic, strong) IBOutlet UIBarButtonItem *forwardButton;
 @property (nonatomic, strong) IBOutlet UIActivityIndicatorView *spinner;
+@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 8645393..1db5e7a 100644
--- a/src/ios/CDVWKInAppBrowser.m
+++ b/src/ios/CDVWKInAppBrowser.m
@@ -564,7 +564,7 @@
 
 - (void)didStartProvisionalNavigation:(WKWebView *)theWebView
 {
-    NSLog(@"didStartProvisionalNavigation");
+    // Do nothing here
 }
 
 - (void)didFinishNavigation:(WKWebView *)theWebView
@@ -730,71 +730,56 @@ BOOL isExiting = NO;
 
     // We add our own constraints, they should not be determined from the frame.
     self.webView.translatesAutoresizingMaskIntoConstraints = NO;
-
-    // Toolbar init without frame
-    self.toolbar = [[UIToolbar alloc] init];
-    self.toolbar.alpha = 1.000;
-    self.toolbar.barStyle = UIBarStyleBlack;
-    self.toolbar.clearsContextBeforeDrawing = NO;
-    self.toolbar.clipsToBounds = NO;
-    self.toolbar.contentMode = UIViewContentModeScaleToFill;
-    self.toolbar.hidden = NO;
-    self.toolbar.multipleTouchEnabled = NO;
-    self.toolbar.opaque = NO;
-    self.toolbar.userInteractionEnabled = YES;
-    if (_browserOptions.toolbarcolor != nil) { // Set toolbar color if user sets it in options
-        self.toolbar.barTintColor = [self colorFromHexString:_browserOptions.toolbarcolor];
-    }
-    if (!_browserOptions.toolbartranslucent) { // Set toolbar translucent to no if user sets it in options
-        self.toolbar.translucent = NO;
+    
+    self.toolbarBackground = [UIView new];
+    // We add our own constraints, they should not be determined from the frame.
+    self.toolbarBackground.translatesAutoresizingMaskIntoConstraints = NO;
+    
+    // Get toolbar background color by options or set default which is white
+    UIColor *toolbarBackgroundColor = _browserOptions.toolbarcolor ? [self colorFromHexString:_browserOptions.toolbarcolor] : UIColor.whiteColor;
+    
+    // Make toolbar semi-transparent by options, default is YES
+    if (_browserOptions.toolbartranslucent) {
+        // On iOS 18 and older, use a semi-transparent color
+        toolbarBackgroundColor = [toolbarBackgroundColor colorWithAlphaComponent:0.6];
     }
-    [self.view addSubview:self.toolbar];
+    
+    self.toolbarBackground.backgroundColor = toolbarBackgroundColor;
+    [self.view addSubview:self.toolbarBackground];
+    
+    self.toolbar = [UIToolbar new];
+    // Remove default background for toolbar on iOS 18 and older, since we provide our own
+    // backround
+    // Remove background
+    [self.toolbar setBackgroundImage:[UIImage new]
+                  forToolbarPosition:UIToolbarPositionAny
+                          barMetrics:UIBarMetricsDefault];
+    // barStyle has to be set to UIBarStyleBlack, otherwhise there would be a gray line left,
+    // after the background was removed
+    self.toolbar.barStyle = UIBarStyleBlack;
     // We add our own constraints, they should not be determined from the frame.
     self.toolbar.translatesAutoresizingMaskIntoConstraints = NO;
-
+    [self.toolbarBackground addSubview:self.toolbar];
+    
     // Background view for address label
-    self.addressBackgroundView = [[UIView alloc] init];
-    self.addressBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
+    self.addressBackgroundView = [UIView new];
+    self.addressBackgroundView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.6];
     self.addressBackgroundView.layer.cornerRadius = 15.0;
-    // Don't draw any content that would be outside the view’s rectangular bounds
-    self.addressBackgroundView.clipsToBounds = YES;
-    [self.view addSubview:self.addressBackgroundView];
     // We add our own constraints, they should not be determined from the frame.
     self.addressBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
+    [self.view addSubview:self.addressBackgroundView];
     
-    self.addressLabel = [[UILabel alloc] init];
-    self.addressLabel.adjustsFontSizeToFitWidth = NO;
-    self.addressLabel.alpha = 1.000;
-    self.addressLabel.backgroundColor = [UIColor clearColor];
-    self.addressLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
-    self.addressLabel.clearsContextBeforeDrawing = YES;
-    // Don't draw any content that would be outside the view’s rectangular bounds
-    self.addressLabel.clipsToBounds = YES;
-    self.addressLabel.contentMode = UIViewContentModeScaleToFill;
-    self.addressLabel.enabled = YES;
-    self.addressLabel.hidden = NO;
-    self.addressLabel.lineBreakMode = NSLineBreakByTruncatingTail;
-
-    if ([self.addressLabel respondsToSelector:NSSelectorFromString(@"setMinimumScaleFactor:")]) {
-        [self.addressLabel setValue:@(10.0/[UIFont labelFontSize]) forKey:@"minimumScaleFactor"];
-    } else if ([self.addressLabel respondsToSelector:NSSelectorFromString(@"setMinimumFontSize:")]) {
-        [self.addressLabel setValue:@(10.0) forKey:@"minimumFontSize"];
-    }
-
-    self.addressLabel.multipleTouchEnabled = NO;
-    self.addressLabel.numberOfLines = 1;
-    self.addressLabel.opaque = NO;
-    self.addressLabel.shadowOffset = CGSizeMake(0.0, -1.0);
+    self.addressLabel = [UILabel new];
     self.addressLabel.text = NSLocalizedString(@"Loading...", nil);
+    self.addressLabel.textColor = UIColor.blackColor;
     self.addressLabel.textAlignment = NSTextAlignmentLeft;
-    self.addressLabel.textColor = [UIColor colorWithWhite:1.000 alpha:1.000];
-    self.addressLabel.userInteractionEnabled = NO;
-    [self.addressBackgroundView addSubview:self.addressLabel];
+    // Truncate at tail of line: "abcd..."
+    self.addressLabel.lineBreakMode = NSLineBreakByTruncatingTail;
     // We add our own constraints, they should not be determined from the frame.
     self.addressLabel.translatesAutoresizingMaskIntoConstraints = NO;
-
+    [self.addressBackgroundView addSubview:self.addressLabel];
+    
     self.spinner = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
-    self.spinner.alpha = 1.000;
     self.spinner.clearsContextBeforeDrawing = NO;
     self.spinner.clipsToBounds = NO;
     self.spinner.contentMode = UIViewContentModeScaleToFill;
@@ -881,12 +866,18 @@ BOOL isExiting = NO;
         [self.webView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]
     ]];
 
-    // Toolbar horizontal constraints
+    // Toolbar background horizontal constraints
     [NSLayoutConstraint activateConstraints:@[
         // Left
-        [self.toolbar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
+        [self.toolbarBackground.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
         // Right
-        [self.toolbar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]
+        [self.toolbarBackground.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]
+    ]];
+
+    // Constrain Toolbar inside Toolbar background view with padding
+    [NSLayoutConstraint activateConstraints:@[
+        [self.toolbar.leadingAnchor constraintEqualToAnchor:self.toolbarBackground.leadingAnchor constant:10.0],
+        [self.toolbar.trailingAnchor constraintEqualToAnchor:self.toolbarBackground.trailingAnchor constant:-10.0]
     ]];
 
     // Address background horizontal constraints with margin
@@ -898,7 +889,7 @@ BOOL isExiting = NO;
         [self.addressBackgroundView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor
                                                                   constant:-15.0]
     ]];
-    
+
     // Constrain Address label inside Address background view with padding
     [NSLayoutConstraint activateConstraints:@[
         [self.addressLabel.topAnchor constraintEqualToAnchor:self.addressBackgroundView.topAnchor constant:10.0],
@@ -928,38 +919,67 @@ BOOL isExiting = NO;
     if (toolbarVisible && !addressLabelVisible) {
         // Toolbar is at top
         if (toolbarIsAtTop) {
-            // Toolbar top to safe area top
-            [self.toolbar.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
-
+            [NSLayoutConstraint activateConstraints:@[
+                // Toolbar background top to top edge
+                [self.toolbarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
+                // Toolbar background bottom to toolbar bottom with margin
+                [self.toolbarBackground.bottomAnchor constraintEqualToAnchor:self.toolbar.bottomAnchor
+                                                                    constant:MARGIN],
+                // Toolbar top to background safe area top
+                [self.toolbar.topAnchor constraintEqualToAnchor:self.toolbarBackground.safeAreaLayoutGuide.topAnchor]
+            ]];
             // Toolbar is at bottom (default)
         } else {
-            // Toolbar bottom to safe area bottom
-            [self.toolbar.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = YES;
+            [NSLayoutConstraint activateConstraints:@[
+                // Toolbar background top to toolbar top with margin, margin must be negative here
+                [self.toolbarBackground.topAnchor constraintEqualToAnchor:self.toolbar.topAnchor
+                                                                 constant:MARGIN*-1],
+                // Toolbar background bottom to bottom edge
+                [self.toolbarBackground.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
+                // Toolbar bottom to background safe area bottom
+                [self.toolbar.bottomAnchor constraintEqualToAnchor:self.toolbarBackground.safeAreaLayoutGuide.bottomAnchor]
+            ]];
         }
     }
 
-    // Case 2: Toolbar not visible, Address label visible
+    // Case 2: Toolbar not visible, Address label visible (default)
     if (!toolbarVisible && addressLabelVisible) {
-        // Address background bottom to safe area bottom
-        [self.addressBackgroundView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = YES;
+        [NSLayoutConstraint activateConstraints:@[
+            // Address background bottom to safe area bottom
+            [self.addressBackgroundView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor]
+        ]];
     }
 
     // Case 3: Toolbar visible and Address label visible
     if (toolbarVisible && addressLabelVisible) {
         // Toolbar is at top
         if (toolbarIsAtTop) {
-            // Toolbar top to safe area top
-            [self.toolbar.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
-            // Address background bottom to safe area bottom
-            [self.addressBackgroundView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = YES;
+            [NSLayoutConstraint activateConstraints:@[
+                // Toolbar background top to top edge
+                [self.toolbarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
+                // Toolbar background bottom to Toolbar bottom with margin
+                [self.toolbarBackground.bottomAnchor constraintEqualToAnchor:self.toolbar.bottomAnchor
+                                                                    constant:MARGIN],
+                // Toolbar top to backround safe area top
+                [self.toolbar.topAnchor constraintEqualToAnchor:self.toolbarBackground.safeAreaLayoutGuide.topAnchor],
+                // Address background bottom to safe area bottom
+                [self.addressBackgroundView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor]
+            ]];
 
             // Toolbar is at bottom (default)
         } else {
-            // Address background bottom to Toolbar top with margin, margin must be negativ here
-            [self.addressBackgroundView.bottomAnchor constraintEqualToAnchor:self.toolbar.topAnchor
-                                                                    constant:MARGIN*-1].active = YES;
-            // Toolbar bottom to safe area bottom
-            [self.toolbar.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = YES;
+            [NSLayoutConstraint activateConstraints:@[
+                // Address background bottom to Toolbar Background top with margin, margin must be negative here
+                [self.addressBackgroundView.bottomAnchor constraintEqualToAnchor:self.toolbarBackground.topAnchor
+                                                                        constant:MARGIN*-1],
+                // Toolbar background top to Toolbar top with margin, margin must be negative here
+                [self.toolbarBackground.topAnchor constraintEqualToAnchor:self.toolbar.topAnchor
+                                                                 constant:MARGIN*-1],
+                // Toolbar background bottom to bottom edge
+                [self.toolbarBackground.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
+                // Toolbar bottom to background safe area bottom
+                [self.toolbar.bottomAnchor constraintEqualToAnchor:self.toolbarBackground.safeAreaLayoutGuide.bottomAnchor]
+            ]];
         }
     }
 }
@@ -982,38 +1002,34 @@ BOOL isExiting = NO;
     BOOL toolbarIsAtTop = [_browserOptions.toolbarposition isEqualToString:kInAppBrowserToolbarBarPositionTop];
     BOOL addressLabelVisible = _browserOptions.location;
     // Height and width of Toolbar and Address Background, which is needed to calculate the inset of the WebView
-    const CGFloat toolbarHeight = self.toolbar.bounds.size.height;
+    const CGFloat toolbarBackgroundHeight = self.toolbarBackground.bounds.size.height;
     const CGFloat addressBackgroundHeight = self.addressBackgroundView.bounds.size.height;
     // Insets for the WebView, which gets calcualted
     CGFloat topInset = 0.0;
     CGFloat bottomInset = 0.0;
-    
+
     if (toolbarVisible) {
         // Toolbar is at top
         if (toolbarIsAtTop) {
-            topInset = toolbarHeight;
+            topInset = toolbarBackgroundHeight - self.view.safeAreaInsets.top;
 
             // Toolbar is at bottom (default)
         } else {
-            bottomInset = toolbarHeight;
+            bottomInset = toolbarBackgroundHeight - self.view.safeAreaInsets.bottom;
         }
     }
 
     if (addressLabelVisible) {
-        bottomInset += addressBackgroundHeight;
-        
-        // If the Toolbar is at bottom, the Address Background View is separated to the Toolbar with
-        // a margin, which must also be added to the inset
+        // The scroll inset should have a margin to the address bar
+        bottomInset += addressBackgroundHeight + MARGIN;
+
+        // Add the margin between address bar and toolbar if toolbar is at bottom and visible
         if (toolbarVisible && !toolbarIsAtTop) {
             bottomInset += MARGIN;
         }
     }
-    
-    // Add additional margin to insets, so there is always room between the overlayed views
-    // and the web content, when the start or end is reached
-    if (topInset) topInset += MARGIN;
-    if (bottomInset) bottomInset += MARGIN;
-    
+
+    // Set insets to webview
     self.webView.scrollView.contentInset = UIEdgeInsetsMake(topInset, 0, bottomInset, 0);
     self.webView.scrollView.verticalScrollIndicatorInsets = UIEdgeInsetsMake(topInset, 0, bottomInset, 0);
 }
@@ -1049,7 +1065,7 @@ BOOL isExiting = NO;
 
 - (void)showToolBar:(BOOL)show atPosition:(NSString *)toolbarPosition
 {
-    self.toolbar.hidden = !show;
+    self.toolbarBackground.hidden = !show;
     _browserOptions.toolbarposition = toolbarPosition; // Keep state consistent if needed
     [self.view setNeedsLayout];
     [self.view layoutIfNeeded];
@@ -1144,6 +1160,7 @@ BOOL isExiting = NO;
 
 - (void)webView:(WKWebView *)theWebView didStartProvisionalNavigation:(WKNavigation *)navigation
 {
+    NSLog(@"didStartProvisionalNavigation");
     // Loading URL, start spinner, update back/forward
     self.addressLabel.text = NSLocalizedString(@"Loading...", nil);
     self.backButton.enabled = theWebView.canGoBack;
@@ -1153,7 +1170,9 @@ BOOL isExiting = NO;
     return [self.navigationDelegate didStartProvisionalNavigation:theWebView];
 }
 
-- (void)webView:(WKWebView *)theWebView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
+- (void)webView:(WKWebView *)theWebView
+decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
+decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
 {
     NSURL *url = navigationAction.request.URL;
     NSURL *mainDocumentURL = navigationAction.request.mainDocumentURL;
@@ -1169,6 +1188,7 @@ BOOL isExiting = NO;
 
 - (void)webView:(WKWebView *)theWebView didFinishNavigation:(WKNavigation *)navigation
 {
+    NSLog(@"didFinishNavigation");
     // Update URL, stop spinner, update back/forward
     self.addressLabel.text = self.currentURL.absoluteString;
     self.backButton.enabled = theWebView.canGoBack;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org