在 UITabBarController 中首次启动时出现自动布局问题

Posted

技术标签:

【中文标题】在 UITabBarController 中首次启动时出现自动布局问题【英文标题】:Issue with auto-layout on first launch within UITabBarController 【发布时间】:2020-06-17 01:10:07 【问题描述】:

我有一个UITabBarController,里面有四个屏幕,类型为“BaseViewController”,它是UIViewController 的一个非常简单的子类,它将包含一个标题,显示一个UILabel,表示用户在哪个屏幕上。例如,当用户单击tabBar 上的主页选项卡时,标签将显示为“HOME”

BaseViewController 的代码:

class BaseViewController: UIViewController 

    let screenIndicationLabel: UILabel = 
        let label = UILabel()
        label.setAttrs(font: "bold", size: 25.0, color: .black)
        label.textAlignment = .center
        return label
    ()

    override func viewDidLoad() 
        super.viewDidLoad()

        view.addSubview(screenIndicationLabel)
        screenIndicationLabel.translatesAutoresizingMaskIntoConstraints = false
        screenIndicationLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        screenIndicationLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        screenIndicationLabel.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
    

UITabBarController 的代码:

class MainTabController: UITabBarController 

    let home = HomeController()
    let browse = BrowseController()
    let bag = BagController()
    let settings = SettingsController()

    override func viewDidLoad() 
        super.viewDidLoad()

        self.viewControllers = [home, browse, bag, settings]
        self.selectedIndex = 0

        self.tabBar.barTintColor = Colors.pink
        self.tabBar.unselectedItemTintColor = Colors.darkPink
        self.tabBar.tintColor = Colors.darkGrey

        home.tabBarItem = homeTab
        browse.tabBarItem = browseTab
        bag.tabBarItem = bagTab
        settings.tabBarItem = settingsTab
    

标签工作正常,但我的问题是在启动应用程序时开始的。作为UITabBarController 的根控制器的主屏幕似乎忽略了UILabel 的这些自动布局约束。显然,在每个屏幕中,标签的文本都设置在viewDidLoad()中。

问题图片(查看屏幕顶部):

当我导航到另一个页面时,这些约束似乎起作用:

然后,当我导航回第一个屏幕时,它现在可以工作了:

如果有人能帮我解决这个问题,我将不胜感激!

【问题讨论】:

你检查过标题是否被限制在安全区域吗? 【参考方案1】:

我刚刚做了一个最小的项目,在 iPhone 11 Pro Max 上进行了测试,因为它是您在屏幕截图中使用的那个,它似乎可以按您的意愿工作:

class BaseViewController: UIViewController 

    let titleLabel: UILabel = 
        $0.textAlignment = .center
        return $0
    (UILabel())

    override func viewDidLoad() 
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(titleLabel)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        titleLabel.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
    


class MainTabController: UITabBarController 

    let home = ViewControllerA()
    let browse = ViewControllerB()
    let bag = ViewControllerC()
    let settings = ViewControllerD()

    override func viewDidLoad() 
        super.viewDidLoad()
        viewControllers = [home, browse, bag, settings]
        selectedIndex = 0
        home.tabBarItem = UITabBarItem(title: "Home", image: nil, selectedImage: nil)
        browse.tabBarItem = UITabBarItem(title: "Browse", image: nil, selectedImage: nil)
        bag.tabBarItem = UITabBarItem(title: "Bag", image: nil, selectedImage: nil)
        settings.tabBarItem = UITabBarItem(title: "Settings", image: nil, selectedImage: nil)
    


class ViewControllerA: BaseViewController 

    override func viewDidLoad() 
        super.viewDidLoad()
        titleLabel.text = "Home"
    


// ...

我想知道如何设置应用窗口的根视图控制器,因为这可能是这里的问题。

您正在使用safeAreaLayoutGuide 将您的视图限制在顶部,以便在任何设备上看起来都很好(因为您已经将高度设置为 50)。

话虽如此,如果您想在所有选项卡屏幕的顶部都有一个标题,我会说使用基类并将标签自己定位在顶部绝对不是最好的方法,并且在事实上,我不建议你这样做。

原因是,您要做的正是导航栏的角色。

如果您想让导航栏与您的屏幕样式相匹配,使其看起来与您的屏幕截图一样,这非常简单,您只需将导航栏的背景颜色更改为透明即可。

不需要基类,您可以简单地设置视图控制器的标题属性,更重要的是您将免费获得所有标题动画!

【讨论】:

以上是关于在 UITabBarController 中首次启动时出现自动布局问题的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的视图在 swiftUI 中首次出现在屏幕上时没有转换

在 appDelegate 中首次展示视图

在 Rails、Coffeescript 中首次单击后禁用链接

UITableViewCell 中的 UITextView 在 `textViewDidBeginEditing` 方法中首次分配失败

在 Angular 中首次渲染时,路由查询参数为空

允许用户在 Firestore 规则中首次尝试写入