0

I'd like to create a header that wouldn't move at all in my application that contains several ViewControllers. My header is simply a view containing a logo (UIImageView), a UIButton and a UILabel. I've heard that I can do that with a UINavigationController or by adding a subview to the UIWindow, but it doesn't work for me (maybe I'm doing it wrong). My main issue is to keep it fixed at the top of the screen (like a hud?) during segue animations, and I would also need to be able to modify the content of the UILabel during the application process.

I work on Xcode 13 with a storyboard for iOS 15 on iPad. Hope I've been clear enough.

EDIT It appears that inserting a view in the UIWindow would be the best solution for me, though I'm not sure how to do that properly. All the examples I find don't work and are deprecated/outdated.

  • 1
    Have you ever made a search engine search? – El Tomato Oct 11 '21 at 09:50
  • Do you need the view to stay on all view controllers or on a specific navigation flow? Keep in mind using the navigation controller will restrict you to use specific segues, and the view will stick to your view controller therefore segue animations will move your header. In case you do not want to stick to these restrictions I'd say go for adding it in the window. But keep in mind it's gonna be harder to account for that extra header space. I'd personally create a custom view that would draw itself and just add it to the corresponding vcs to account for the constraints correctly. – marc Oct 11 '21 at 09:51
  • Feel free to explain more and show us what you need specifically. I'll help you – marc Oct 11 '21 at 09:52
  • @marc As I'm using a custom segue so you're probably right. I've tried to add my header view to the window in the SceneDelegate.scene function but it doesn't appear, I think I should bring it to front but I don't know where. – HydroMésange Oct 11 '21 at 10:16
  • @ElTomato any helpful link would be great, I've searched a lot but found nothing that worked for me. I feel like many things are outdated but I'm prolly wrong. – HydroMésange Oct 11 '21 at 10:19

2 Answers2

0

You can create a custom UITabBarController and then add it to SceneDelegate as -

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        
        let vc = CustomTab()
        self.window?.rootViewController = vc
        self.window?.makeKeyAndVisible()
        .......

In custom TabBar add all your navigation controllers as -

viewControllers = [nav1, nav2, nav3, nav4]

And in every view controller class you can hide, change or modify the tabbar prperties.

Imran0001
  • 580
  • 4
  • 11
0

So finally I succeeded using the method of Imran to which I added few things to match what I needed.

I have a singleton class for my header ViewController that contains the elements I needed inside of it.

let HEADER = STORYBOARD.instantiateViewController(withIdentifier: "HeaderLayer") as? HeaderViewController

class HeaderViewController: UIViewController {

    @IBOutlet weak var ThemeLabel: UILabel!
    @IBOutlet weak var DifficultyImage: UIImageView!
    @IBOutlet weak var ExitButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...
    }

    // Methods
}

And here's how I put my header in the UIWindow to make it appear at the top of the screen, where it will stay fixed even during segue animations. I change the frame because in full screen it would disable the interactions for the views underneath.

let STORYBOARD = UIStoryboard(name: "Main", bundle: nil)

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
        HEADER!.view.frame = CGRect(x: 0, y: 0, width: 1366, height: 142)
        window?.addSubview(HEADER!.view)
        window?.makeKeyAndVisible()
    
        // ...
    }
    // ...
}

Then it's necessary to bring the header to front everytime one of my ViewControllers appears.

class ViewController: UIViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    
        let window = UIApplication.shared.keyWindow
        window?.bringSubviewToFront(HEADER!.view)
    
        // ...
    }
}

I'm not using any UINavigationController or UITabBarController, but it is possible with this method.

The only problem I encountered is that UIApplication.shared.keywindow is deprecated. But it doesn't seem to cause any issue and I didn't find a solution yet.