Search code examples
iosswiftautolayoutuitabbarcontrollerorientation

Layout fails to update when going back to view controller with different device orientation (UITabBarController)


My app has a main UITabBarController with 5 tabs (each one is a UINavigationController). The tabs contain various UI elements, such as UITableViews (with and without custom cells), UISegmentedControls, and others. When a view/tab is visible on screen and I rotate the device, the layout is adjusted as expected and everything works fine. However, now I do the following:

  1. Go to any tab, say tab A
  2. Navigate to another tab, say tab B
  3. While still on tab B, rotate device, for example from portrait to landscape
  4. Go back to tab A while still in the new orientation

The layout of the view of tab A is now messed up. For example, there is a huge margin on top of the tableview, or the UISegmentedControl is not visible at all. For the case of the UITableView, the layout finally updates when I scroll for a bit. For other views, the only possibility to get the correct layout is to rotate the device again when the view is visible.

Some of the views are created programmatically, some in storyboard. So it does not seem to matter which method is chose, the problem exists in both. A similar question can be found here, but it has no answers so I was forced to ask again.

Has anyone experienced a similar issue and knows how to fix this problem?

Edit: Here is a MWE. View Controller of first tab:

import UIKit
class FirstViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

// MARK: - table view
let tableView: UITableView = {
    let view = UITableView(frame: .zero, style: .grouped)
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

override func viewDidLoad() {
    super.viewDidLoad()
    
    // set background color of tableview
    tableView.backgroundColor = .clear
    view.backgroundColor = .systemGroupedBackground
    
    // register tableview cell
    tableView.register(TabOneTableViewCell.self, forCellReuseIdentifier: "TestCellOne")
                    
    // remove separator
    tableView.separatorStyle = .none
    
    // add pull to refresh
    tableView.refreshControl = UIRefreshControl()
    tableView.refreshControl?.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged)
    tableView.refreshControl?.tintColor = .white
    
    tableView.dataSource = self
    tableView.delegate = self
    
    view.addSubview(tableView)
    
    NSLayoutConstraint.activate([
        
        // constraints for table view
        tableView.topAnchor.constraint(equalTo: view.topAnchor),
        tableView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor),
        tableView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor),
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        
    ])
                     
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
    return 10
            
}

func numberOfSections(in tableView: UITableView) -> Int {
    
    return 1
    
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    
    // header view
    let headerView: UITableViewHeaderFooterView = {
        let view = UITableViewHeaderFooterView()
        return view
    }()
    
    // button
    let headerButton: UIButton = {
        let button = UIButton()
        button.setTitle("Some Settings", for: .normal)
        button.setTitleColor(UIColor.label, for: .normal)
        button.setImage(UIImage(systemName: "chevron.right"), for: .normal)
        button.tintColor = UIColor.label
        button.titleLabel?.font = .systemFont(ofSize: 12, weight: .regular)
        button.contentHorizontalAlignment = .right
        button.semanticContentAttribute = .forceRightToLeft
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    // icon
    let headerIcon: UIImageView = {
        let image = UIImageView()
        image.image = UIImage(systemName: "bell.badge")
        image.translatesAutoresizingMaskIntoConstraints = false
        image.tintColor = .red
        image.contentMode = .scaleAspectFit
        return image
    }()
    
    view.addSubview(headerView)
    headerView.addSubview(headerIcon)
    headerView.addSubview(headerButton)
            
    // constraints
    NSLayoutConstraint.activate([
        // constraints for the header view
        headerView.topAnchor.constraint(equalTo: view.topAnchor),
        headerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
        headerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
        headerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        
        // button constraints
        headerButton.topAnchor.constraint(equalTo: headerView.topAnchor),
        headerButton.trailingAnchor.constraint(equalTo: headerView.trailingAnchor, constant: -15),
        headerButton.bottomAnchor.constraint(equalTo: headerView.bottomAnchor),
        
        // icon constraints
        headerIcon.centerYAnchor.constraint(equalTo: headerButton.centerYAnchor),
        headerIcon.trailingAnchor.constraint(equalTo: headerButton.leadingAnchor, constant: -3),
    ])
    
    return headerView
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    
    return 80
    
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let cell = tableView.dequeueReusableCell(withIdentifier: "TestCellOne", for: indexPath) as! TabOneTableViewCell
    cell.backgroundColor = UIColor.clear
    cell.selectionStyle = .none
    cell.setCellOne()
    return cell
            
}

@objc func didPullToRefresh() {
    
}

}

TableViewCell of first tab:

import UIKit

class TabOneTableViewCell: UITableViewCell {

// MARK: - card view
let cardView : UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = UIColor.lightGray
    view.layer.cornerRadius = 12.5
    view.layer.shadowOffset = CGSize(width: 0, height: 5)
    view.layer.shadowRadius = 5
    view.layer.shadowOpacity = 0.3
    return view
}()

// MARK: - post image view
let postImageView: UIImageView = {
    let view = UIImageView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.clipsToBounds = true
    view.contentMode = .scaleAspectFill
    view.backgroundColor = .cyan
    view.layer.cornerRadius = 12.5
    view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
    return view
}()

// MARK: - title Label
let titleLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.numberOfLines = 0
    label.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
    return label
}()

// MARK: - date icon
let dateIcon: UIImageView = {
    let view = UIImageView()
    view.image = UIImage(systemName: "calendar.badge.clock")
    view.contentMode = .scaleAspectFill
    view.translatesAutoresizingMaskIntoConstraints = false
    view.tintColor = UIColor.red
    return view
}()

// MARK: - date label
let dateLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.numberOfLines = 0
    label.font = UIFont.systemFont(ofSize: 15, weight: .regular)
    label.textColor = UIColor.red
    return label
}()

// MARK: - content preview
let contentPreview: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 15, weight: .regular)
    label.numberOfLines = 3
    return label
}()

func setCellOne() {
    
    // set background color of cell
    contentView.backgroundColor = .clear
    
    // add card view to contentview
    contentView.addSubview(cardView)
    
    // add views to cardview
    cardView.addSubview(titleLabel)
    cardView.addSubview(dateIcon)
    cardView.addSubview(dateLabel)
    cardView.addSubview(contentPreview)
    cardView.addSubview(postImageView)
    
    NSLayoutConstraint.activate([
        
        // constraints for card view
        cardView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0),
        cardView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
        cardView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
        cardView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20),
                    
        // constraints for imageview
        postImageView.topAnchor.constraint(equalTo: cardView.topAnchor, constant: 0),
        postImageView.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 0),
        postImageView.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: 0),
        postImageView.heightAnchor.constraint(equalTo: postImageView.widthAnchor, multiplier: 0.65),
        
        // constraints for date icon
        dateIcon.topAnchor.constraint(equalTo: postImageView.bottomAnchor, constant: 15),
        dateIcon.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 10),
        dateIcon.widthAnchor.constraint(equalToConstant: 20),
        dateIcon.heightAnchor.constraint(equalToConstant: 20),
        
        // constraints for date label
        dateLabel.centerYAnchor.constraint(equalTo: dateIcon.centerYAnchor),
        dateLabel.leadingAnchor.constraint(equalTo: dateIcon.trailingAnchor, constant: 10),
        dateLabel.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -10),
        
        // constraints for title label
        titleLabel.topAnchor.constraint(equalTo: dateLabel.bottomAnchor, constant: 15),
        titleLabel.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 10),
        titleLabel.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -10),
        
        // constraints for content preview
        contentPreview.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15),
        contentPreview.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 10),
        contentPreview.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -10),
        contentPreview.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -10),
        
    ])
    
    // set title label
    titleLabel.text = "This is a title"
    
    // set the content preview label
    contentPreview.text = "The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. The content goes here. "
    
    // set date label
    dateLabel.text = "This is a date"
    
}

}

View Controller of second tab:

import UIKit

class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    
    // set background color
    view.backgroundColor = .systemGroupedBackground
    tableView.backgroundColor = .clear
    
    // register tableview cell
    tableView.register(TabTwoTableViewCell.self, forCellReuseIdentifier: "TableCellTwo")
    
    // add pull to refresh
    tableView.refreshControl = UIRefreshControl()
    tableView.refreshControl?.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged)
    tableView.refreshControl?.tintColor = UIColor.white
    
    // If all four constraints are set in storyboard, there are weird glitches with the refreshcontrol. Setting only 3 constraints in storyboard and the last one here fixed it.
    NSLayoutConstraint.activate([
        tableView.topAnchor.constraint(equalTo: view.topAnchor),
    ])
    
    tableView.dataSource = self
    tableView.delegate = self
    
    setTableviewFooter()
    
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
    switch section {
    case 1:
        return 3
    case 2:
        return 2
    case 3:
        return 3
    default:
        return 0
    }
    
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    
    if section == 0 {
        return ""
    }
    else {
        return "Title Section \(section)"
    }
    
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            
    // only for first section
    if section == 0 {
        
        // blur effects
        let _: UIBlurEffect = {
            let blur = UIBlurEffect(style: .light)
            return blur
        }()
        let _: UIVisualEffectView = {
            let blur = UIVisualEffectView()
            return blur
        }()
        
        // header view
        let headerView: UITableViewHeaderFooterView = {
            let view = UITableViewHeaderFooterView()
            return view
        }()
        
        // button
        let headerButton: UIButton = {
            let button = UIButton()
            button.setTitle("Some settings", for: .normal)
            button.setTitleColor(UIColor.label, for: .normal)
            button.setImage(UIImage(systemName: "chevron.right"), for: .normal)
            button.tintColor = UIColor.label
            button.titleLabel?.font = .systemFont(ofSize: 12, weight: .regular)
            button.contentHorizontalAlignment = .right
            button.semanticContentAttribute = .forceRightToLeft
            button.translatesAutoresizingMaskIntoConstraints = false
            return button
        }()
        
        // icon
        let headerIcon: UIImageView = {
            let image = UIImageView()
            image.image = UIImage(systemName: "calendar.badge.plus")
            image.translatesAutoresizingMaskIntoConstraints = false
            image.tintColor = .red
            image.contentMode = .scaleAspectFit
            return image
        }()
        
        view.addSubview(headerView)
        headerView.addSubview(headerIcon)
        headerView.addSubview(headerButton)
                    
        // constraints
        NSLayoutConstraint.activate([
            // constraints for the header view
            headerView.topAnchor.constraint(equalTo: view.topAnchor),
            headerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            headerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            headerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            
            // button constraints
            headerButton.topAnchor.constraint(equalTo: headerView.topAnchor),
            headerButton.trailingAnchor.constraint(equalTo: headerView.trailingAnchor, constant: -15),
            headerButton.bottomAnchor.constraint(equalTo: headerView.bottomAnchor),
            
            // icon constraints
            headerIcon.centerYAnchor.constraint(equalTo: headerButton.centerYAnchor),
            headerIcon.trailingAnchor.constraint(equalTo: headerButton.leadingAnchor, constant: -3),
        ])
        
        // return the date
        return headerView
        
    }
    else {
        return nil
    }
    
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    
    return 40
    
}

func numberOfSections(in tableView: UITableView) -> Int {
    
    return 4
    
}
 
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let cell = tableView.dequeueReusableCell(withIdentifier: "TableCellTwo", for: indexPath) as! TabTwoTableViewCell
    cell.selectionStyle = .none
    cell.backgroundColor = .clear
    cell.accessoryType = .disclosureIndicator
    tableView.separatorStyle = .singleLine
    cell.setTestCellTwo()
    return cell
            
}

// MARK: - function for pull to refresh
@objc private func didPullToRefresh() {
    
}

// MARK: - setting the footer for the table
private func setTableviewFooter() {
    
    let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 100))
    footerView.backgroundColor = UIColor.clear
    let footerLabel = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 100))
    footerLabel.text = "Some text goes\nhere"
    footerLabel.numberOfLines = 0
    footerLabel.backgroundColor = .clear
    footerLabel.font = .systemFont(ofSize: 13, weight: .regular)
    footerLabel.textColor = .secondaryLabel
    footerLabel.textAlignment = .center
    footerView.addSubview(footerLabel)
    
    tableView.tableFooterView = footerView
}

}

TableViewCell of second Tab:

import UIKit

class TabTwoTableViewCell: UITableViewCell {

// MARK: - card view
let cardView : UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .yellow
    view.layer.cornerRadius = 12.5
    view.layer.shadowOffset = CGSize(width: 0, height: 5)
    view.layer.shadowRadius = 5
    view.layer.shadowOpacity = 0.3
    return view
}()

// MARK: - stack view inside of card view
let stackViewInCardView: UIStackView = {
    let view = UIStackView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.distribution = .fillProportionally
    view.alignment = .center
    view.axis = .vertical
    return view
}()

// MARK: - stack view next to card view
let stackView: UIStackView = {
    let view = UIStackView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.distribution = .fillProportionally
    view.alignment = .leading
    view.axis = .vertical
    return view
}()

// MARK: - label for start date day
let startDateDayLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 36, weight: .heavy)
    label.textColor = .black
    label.numberOfLines = 1
    return label
}()

// MARK: - label for start date month
let startDateMonthLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 17, weight: .regular)
    label.textColor = .black
    label.numberOfLines = 1
    return label
}()

// MARK: - label for end date
let endDateLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 17, weight: .regular)
    label.textColor = UIColor.black
    label.numberOfLines = 1
    return label
}()

// MARK: - label for title
let titleLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
    label.textColor = UIColor.label
    label.numberOfLines = 0
    return label
}()

// MARK: - stack view for time
let timeStackView: UIStackView = {
    let view = UIStackView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.distribution = .fillProportionally
    view.alignment = .center
    view.axis = .horizontal
    view.spacing = 10
    return view
}()

// MARK: - label for time
let timeLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 15, weight: .regular)
    label.textColor = UIColor.label
    label.numberOfLines = 1
    return label
}()

// MARK: - imageview for the time icon
let timeIcon: UIImageView = {
    let icon = UIImageView()
    icon.image = UIImage(systemName: "clock")
    icon.tintColor = UIColor.label
    icon.contentMode = .scaleAspectFill
    icon.translatesAutoresizingMaskIntoConstraints = false
    return icon
}()

// MARK: - stack view for description
let descriptionStackView: UIStackView = {
    let view = UIStackView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.distribution = .fillProportionally
    view.alignment = .center
    view.axis = .horizontal
    view.spacing = 10
    return view
}()

// MARK: - label for description
let descriptionLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 15, weight: .regular)
    label.textColor = UIColor.label
    label.numberOfLines = 1
    return label
}()

// MARK: - imageview for the time icon
let descriptionIcon: UIImageView = {
    let icon = UIImageView()
    icon.image = UIImage(systemName: "pencil")
    icon.tintColor = UIColor.label
    icon.contentMode = .scaleAspectFill
    icon.translatesAutoresizingMaskIntoConstraints = false
    return icon
}()

func setTestCellTwo() {
    
    // add the card view
    contentView.addSubview(cardView)
    
    // add the stack view inside of the card view
    cardView.addSubview(stackViewInCardView)
            
    // add to stackview inside of card view
    stackViewInCardView.addArrangedSubview(startDateDayLabel)
    stackViewInCardView.addArrangedSubview(startDateMonthLabel)
    stackViewInCardView.addArrangedSubview(endDateLabel)
    
    // add stack view next to card view
    contentView.addSubview(stackView)
    
    // add labels and icons to stack view
    timeStackView.addArrangedSubview(timeIcon)
    timeStackView.addArrangedSubview(timeLabel)
    descriptionStackView.addArrangedSubview(descriptionIcon)
    descriptionStackView.addArrangedSubview(descriptionLabel)
    
    // add views to stack view
    stackView.addArrangedSubview(titleLabel)
    stackView.addArrangedSubview(timeStackView)
    stackView.addArrangedSubview(descriptionStackView)
    
    NSLayoutConstraint.activate([
        
        // constraints for card view
        cardView.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor, constant: 10),
        cardView.leadingAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.leadingAnchor, constant: 15),
        cardView.widthAnchor.constraint(equalToConstant: 120),
        cardView.heightAnchor.constraint(equalToConstant: 120),
        cardView.bottomAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.bottomAnchor, constant: -10),
        
        // constraints for stack view in card view
        stackViewInCardView.topAnchor.constraint(equalTo: cardView.topAnchor, constant: 10),
        stackViewInCardView.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 10),
        stackViewInCardView.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -10),
        stackViewInCardView.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -10),
        
        // constraints for stack view next to card view
        stackView.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor, constant: 10),
        stackView.leadingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: 10),
        stackView.trailingAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.trailingAnchor, constant: -10),
        stackView.bottomAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.bottomAnchor, constant: -10),
        
        // constraints for time icon
        timeIcon.widthAnchor.constraint(equalToConstant: 20),
        timeIcon.heightAnchor.constraint(equalToConstant: 20),
        
        // constraints for description icon
        descriptionIcon.widthAnchor.constraint(equalToConstant: 20),
        descriptionIcon.heightAnchor.constraint(equalToConstant: 20),
    ])
    
    // set description label
    descriptionLabel.text = "This is a description"
    
    // set title label
    titleLabel.text = "This is a title"
    
    // set start day label
    startDateDayLabel.text = "20."
    
    // set start month label
    startDateMonthLabel.text = "July"
    
    // set end date label
    endDateLabel.text = "End date"

    // set time label
    timeLabel.text = "11:00 - 12:00"
    
    
}

}

My UINavigationControllers both look like this:

import UIKit

class TabOneNavigationController: UINavigationController {

// set icons to white
override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

override func viewDidLoad() {
    super.viewDidLoad()

}

override func viewWillAppear(_ animated: Bool) {
    
    if #available(iOS 13.0, *) {
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.configureWithOpaqueBackground()
        navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.backgroundColor = .blue
        navigationBar.standardAppearance = navBarAppearance
        navigationBar.scrollEdgeAppearance = navBarAppearance
    }

}

}

The resulting problems are shown in the image.


Solution

  • This is a "whoops" issue :(

    First, we can reproduce it with a much simpler example (no need for any table views or cells)...

    With a fresh UITabBarController -- and the default two view controllers -- assign the controllers to FirstVC and SecondVC and embed each controller in a UINavigationController. Set the class of both navigation controllers to TabOneNavigationController...

    FirstVC and SecondVC

    class FirstVC: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            let label: UILabel = {
                let v = UILabel()
                v.text = "First TAB"
                v.textAlignment = .center
                v.backgroundColor = .cyan
                v.translatesAutoresizingMaskIntoConstraints = false
                return v
            }()
            view.addSubview(label)
            let g = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                label.topAnchor.constraint(equalTo: g.topAnchor),
                label.leadingAnchor.constraint(equalTo: g.leadingAnchor),
                label.heightAnchor.constraint(equalToConstant: 80.0),
                label.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.5),
            ])
        }
    }
    class SecondVC: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            let label: UILabel = {
                let v = UILabel()
                v.text = "Second TAB"
                v.textAlignment = .center
                v.backgroundColor = .yellow
                v.translatesAutoresizingMaskIntoConstraints = false
                return v
            }()
            view.addSubview(label)
            let g = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                label.topAnchor.constraint(equalTo: g.topAnchor),
                label.leadingAnchor.constraint(equalTo: g.leadingAnchor),
                label.heightAnchor.constraint(equalToConstant: 80.0),
                label.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.5),
            ])
        }
    }
    

    Your original TabOneNavigationController

    class TabOneNavigationController: UINavigationController {
        
        // set icons to white
        override var preferredStatusBarStyle: UIStatusBarStyle {
            return .lightContent
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        override func viewWillAppear(_ animated: Bool) {
            if #available(iOS 13.0, *) {
                let navBarAppearance = UINavigationBarAppearance()
                navBarAppearance.configureWithOpaqueBackground()
                navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
                navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
                navBarAppearance.backgroundColor = .blue
                navigationBar.standardAppearance = navBarAppearance
                navigationBar.scrollEdgeAppearance = navBarAppearance
            }
            
        }
        
    }
    

    When run, we get this:

    enter image description here

    select Tab2:

    enter image description here

    rotate device:

    enter image description here

    select Tab1:

    enter image description here

    As we see, there is a "gap" above the label.

    Now, edit viewWillAppear() in TabOneNavigationController:

    override func viewWillAppear(_ animated: Bool) {
    
        // add this line to fix the layout problem
        super.viewWillAppear(animated)
        
        if #available(iOS 13.0, *) {
            let navBarAppearance = UINavigationBarAppearance()
            navBarAppearance.configureWithOpaqueBackground()
            navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
            navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
            navBarAppearance.backgroundColor = .blue
            navigationBar.standardAppearance = navBarAppearance
            navigationBar.scrollEdgeAppearance = navBarAppearance
        }
        
    }
    

    Run it again, and when we go back to Tab1:

    enter image description here

    As a side note: you can put your navBarAppearance code inside viewDidLoad() so it only runs once instead of every time you switch tabs.