'Why does UIToolBar turn transparent/translucent when table view scrolls under it

I have a UITableViewController and when the user taps an "edit" button, I display a toolbar at the bottom of the screen. I create a shadow on top of the toolbar. It looks great (until I changed the color to make it more obvious shat's going wrong). When I scroll the table up, as soon as the bottom of the table comes out from behind the toolbar, the toolbar colors all become transparent or do something that looks transparent.

Here is a picture of the screen when the table has data that flows under the toolbar:

enter image description here

Here is a picture of the screen as I drag the table up and the last item is only partly under the toolbar:

enter image description here

Finally, when I drag the table as fr up as I can and the last item is completely above the toolbar, I get this:

enter image description here

It is obvious that the toolbar background is changing opacity as the table is scrolling. I need to disable this. I have tried various combinations of checking and unchecking the "under bottom bars" and "under opaque bars" in the storyboard. I have tried adding an empty footer and not adding an empty footer to the table. Here is the code that creates the toolbar. Note that I'm using a table view controller within a tab bar controller and hiding the tab bar when the user edits the table:

public func setEditingWithTabController( _ editing: Bool, animated: Bool, tabController: UITabBarController ) {
    if navigationController == nil || navigationController!.toolbar == nil {
        return
    }
    navigationController!.setToolbarHidden( !editing, animated: true )
    
    var items = [UIBarButtonItem]()
    
    let flexible = UIBarButtonItem( barButtonSystemItem: .flexibleSpace, target: self, action: nil )
    deleteButton = UIBarButtonItem(title: Strings.Delete.localized, style: .plain, target: self, action: #selector(didPressDelete))
    deleteAllButton = UIBarButtonItem(title: "Delete All", style: .plain, target: self, action: #selector(didPressDeleteAll))
    items.append( deleteAllButton! )
    items.append( flexible )
    items.append( deleteButton! )
    tabController.setToolbarItems( items, animated: false ) // toolbar gets its items form the current view controller
    
    let bar = navigationController!.toolbar!
    bar.backgroundColor = AppSettings.appBackgroundColor.isDark ? AppSettings.appBackgroundColor.lighten( amount: 0.05 ) : AppSettings.appBackgroundColor.darken( amount: 0.05 )
    bar.barTintColor = AppSettings.appBackgroundColor.isDark ? AppSettings.appBackgroundColor.lighten( amount: 0.05 ) : AppSettings.appBackgroundColor.darken( amount: 0.05 )
    
    bar.layer.shadowColor = UIColor.red.cgColor //AppSettings.appBackgroundColor.isDark ? UIColor.lightGray.cgColor :  UIColor.lightGray.cgColor
    bar.layer.shadowOpacity = AppSettings.appBackgroundColor.isDark ? 0 : 0.5
    bar.layer.shadowOffset = CGSize.zero
    bar.layer.shadowRadius = AppSettings.appBackgroundColor.isDark ? 0 : 20
    bar.layer.borderColor = UIColor.clear.cgColor
    bar.layer.borderWidth = 0
    
    bar.clipsToBounds = false
    bar.isTranslucent = false
    bar.isOpaque = true

    tableView.setEditing( editing, animated: true )
    
    if editing {
        refreshControl?.removeFromSuperview()
        tableView.backgroundView = nil
    } else {
        refreshControl = UIRefreshControl()
        refreshControl!.addTarget( self, action: #selector( refreshData(_:) ), for: .valueChanged )
        tableView.backgroundView = refreshControl
    }
}

This same thing happened before I added any of the shadow layer code but was much less obvious with the background simply changing from white to light gray when I scrolled the table.

The function above gets called when the user taps the "edit" button in the app header. Obviously I don't need to configure the toolbar every time this happens and especially when hiding it - I'll worry about fixing all of that later. I need to figure out why I can't get a clean unchanging toolbar. heck, I can't even seem to get rid of the gray line at the top of the toolbar even though I'm setting the border size to zero. This thing has a mind of its own!

[CORRECTION]...

I was not setting a background color. Now when I set a background color, I get the translucency only under the toolbar in the safe area inset like this:

enter image description here



Solution 1:[1]

In iOS 15, UIKit has extended the usage of the scrollEdgeAppearance, which by default produces a transparent background, to all navigation bars. The background is controlled by when your scroll view scrolls content behind the navigation bar. Your screenshots indicate that you are scrolled to the top, and so the navigation bar has selected its scrollEdgeAppearance over the standardAppearance that it would use when scrolled, and on previous versions of iOS. To restore the old look, you must adopt the new UINavigationBar appearance APIs, UINavigationBarAppearance. Remove your existing customizations and do something like this:

let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = <your tint color>
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance

In the general case, it is the last line navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance, which resolves the issue by having the UINavigationBar use the same appearance for both its standard and edge states. Also note that this will cause the scroll view to underlap the navigation bar – we recommend against setting UINavigationBar.isTranslucent = true. You can also use the appearance proxy with the code above, but substituting navigationBar.appearance().scrollEdgeAppearance = appearance for the last line (as you are constructing your own appearance object – the idea is to just make sure both scrollEdge and standard appearances are the same).

Credit: https://developer.apple.com/forums/thread/682420

Same can be achieved for Tabbar

let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = <your tint color>
self.tabBarController?.tabBar.standardAppearance = appearance;
self.tabBarController?.tabBar.scrollEdgeAppearance = self.tabBarController?.tabBar.standardAppearance

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Abu Ul Hassan