Search code examples
iosuitableviewautolayoutpopoversize-classes

Popover controller does not respect device size class


I'm working on an app that uses a couple of UITableView as a popover. I have custom cell set up with labels and I'm using size classes to size the fonts larger when viewing on an iPad. The sizing of the fonts is not working on the popover. Regardless of the device I use, it is obeying the default font size. If I use the same cell and show it in a UITableView that is not a popover, the font adjusts according to the device on which it's displayed

This is my custom cell. It's very simple, with just a label.

enter image description here

This is how I have the fonts set up.

enter image description here

As you can see, I have the font for wRhR set up much larger than the default.

When I run this on an iPad, this is the size of the font in the cells when I am showing the table.

enter image description here

And this is the size of the font in the cells in the popover.

enter image description here

If I adjust the default font size larger, it is reflected in the popover. This is what it looks like when I set the default font size to 30.

enter image description here

How can I get the UITableViewCell label to obey the font set for the wRhR size class when used on a popover?

After adding this, I've noticed one inconsistency. On the popover used in this method, there is a large amount of space between the top of the popover and the table. It looks like this:

enter image description here

Displaying a popover with a tableview without a custom cell looks like this.

enter image description here

I think that the blank area at the top is the navbar. If possible, I'd like it to look like the second image.

Another edit: I figured it out. Adding this to the code for the popover fixes it:

navController.setNavigationBarHidden(true, animated: false)

Solution

  • One option would be to use a custom UINavigationController:

    class PopoverNavController: UINavigationController {
    
        var customTraitCollection: UITraitCollection?
    
        convenience init(rootViewController: UIViewController, traitCollection: UITraitCollection? = nil) {
            self.init(rootViewController: rootViewController)
            customTraitCollection = traitCollection
        }
    
        override var traitCollection: UITraitCollection {
            if let customTraitCollection = customTraitCollection {
                return customTraitCollection
            }
            return super.traitCollection
        }
    }
    

    You can use it like this:

    let storyboard = UIStoryboard(name: "Main", bundle: .main)
    guard let popoverController = storyboard.instantiateViewController(withIdentifier: "PopoverController") as? PopoverController else {
        return
    }
    // Here we set the override trait collection
    let navController = PopoverNavController(rootViewController: popoverController, traitCollection: traitCollection)
    navController.modalPresentationStyle = .popover
    let popover = navController.popoverPresentationController
    popoverController.preferredContentSize = preferredContentSize
    popover?.sourceView = sourceView
    popover?.sourceRect = sourceRect
    popover?.permittedArrowDirections = .up
    present(navController, animated: true)
    

    This way the popover controller gets the same trait collection as its parent. If this trait collection does not suit your needs you can also specify a custom trait collection, like this:

    let customTraitCollection = UITraitCollection(horizontalSizeClass: .regular)
    let navController = PopoverNavController(rootViewController: popoverController, traitCollection: customTraitCollection)