【问题标题】:Swift - Programmatically refresh constraintsSwift - 以编程方式刷新约束
【发布时间】:2020-03-04 12:44:46
【问题描述】:

我的 VC 以 stackView 开头,并附有 Align Bottom to Safe Area

我有tabBar,但一开始是隐藏的tabBar.isHidden = true

稍后当tabBar出现时,它会隐藏stackView

所以我需要在tabBar.isHidden = false 之后刷新约束的函数


当我使用tabBar.isHidden = false 启动应用程序时,stackView 会正确显示。


尝试了每个功能,例如:stackView.needsUpdateConstraints() , updateConstraints() , setNeedsUpdateConstraints(),但没有成功。


现在我正在以编程方式更改底部,但是当我切换 tabBarIndex 并返回到具有更改底部约束的那个时,它会检测到 tabBar 并将 stackView 提升到另一个视图(未附加约束)下。就像是再次刷新了约束。我正在隐藏并显示这个带有开/关屏幕约束的 stackView。

tabBar.isHidden = false后需要刷新约束,但是约束没有检测到tabBar的出现。

正如我提到的在 tabBars 之间切换解决了这个问题,所以在切换后执行一些代码来检测 tabBar。有人知道这个代码吗?我尝试调用方法 viewDidLayoutSubviews 和 viewWillLayoutSubviews 没有成功...有什么建议吗?

【问题讨论】:

  • 你必须创建一个底部对齐的出口并在显示标签栏时更改其常量值。
  • 不要这个方法。我想刷新约束。
  • 您的tabBar 是否已添加到您的视图中?或者,您的 VC 是隐藏标签栏的UITabBarController 的标签之一吗?或者,您的 VC 是否嵌入在导航控制器中,并且您将底部栏称为 tabBar
  • UITabBarController 是 MAIN Controller,tabBar 的索引 0 上是 stackView

标签: swift nslayoutconstraint tabbar


【解决方案1】:

这种业余方法修复了我的错误...:D

tabBarController!.selectedIndex = 1
tabBarController!.selectedIndex = 0

或带有扩展名

extension UITabBarController {

    // Basically just toggles the tabs to fix layout issues
    func forceConstraintRefresh() {
    
        // Get the indices we need
        let prevIndex = selectedIndex
        var newIndex = 0
    
        // Find an unused index
        let items = viewControllers ?? []
        find: for i in 0..<items.count {
            if (i != prevIndex) {
                newIndex = i
                break find
            }
        }
    
        // Toggle the tabs
        selectedIndex = newIndex
        selectedIndex = prevIndex
    
    }

}

用法(切换暗/亮模式时调用):

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    
    tabBarController?.forceConstraintRefresh()

}

【讨论】:

  • 这可能是一个 hack,但实际上效果很好!
【解决方案2】:

如果你想更新视图的布局,你可以试试layoutIfNeeded()函数。

【讨论】:

    【解决方案3】:

    更新stackView约束后调用此方法:

    stackView.superview?.layoutIfNeeded()
    

    【讨论】:

    • 他没有更新约束......他只是希望他的堆栈随着标签栏兄弟的显示和隐藏而调整
    • 不用担心,我会花掉我的一些声誉来获得赏金,一些专业人士会回答这个问题:D
    【解决方案4】:

    Apple 的 Human Interface Guidelines 表示不应该乱用 Tab Bar,这就是为什么(我猜)设置 tabBar.isHidden 不能正确更新视图层次结构的其余部分。

    快速搜索提供了各种UITabBarController 扩展来显示/隐藏标签栏...但它们似乎都将标签栏向下推到屏幕外,而不是设置其.isHidden 属性。可能适合也可能不适合您使用。

    我从您的 cmets 中假设您的选项卡索引 0 中的 VC 有一个按钮(或其他操作)来显示/隐藏 tabBar?

    如果是这样,这是一种可能完成工作的方法....

    在你的项目中添加这个enum

    enum TabBarState {
        case toggle, show, hide
    }
    

    并将这个函数放在那个视图控制器中:

    func showOrHideTabBar(state: TabBarState? = .toggle) {
    
        if let tbc = self.tabBarController {
            let b: Bool = (state == .toggle) ? !tbc.tabBar.isHidden : state == .hide
            guard b != tbc.tabBar.isHidden else {
                return
            }
            tbc.tabBar.isHidden = b
            view.frame.size.height -= 0.1
            view.setNeedsLayout()
            view.frame.size.height += 0.1
        }
    }
    

    你可以这样称呼它:

    // default: toggles isHidden
    showOrHideTabBar()
    
    // toggles isHidden
    showOrHideTabBar(state: .toggle)
    
    // SHOW tabBar (if it's hidden)
    showOrHideTabBar(state: .show)
    
    // HIDE tabBar (if it's showing)
    showOrHideTabBar(state: .hide)
    

    期望在设置 tabBar 的 .isHidden 属性后简单地将 .setNeedsLayout().layoutIfNeeded() 配对应该可以完成这项工作,但显然不是。

    快速的框架高度变化(结合.setNeedsLayout()确实触发了自动布局,但是高度变化是不可见的。

    注意:这是在一台设备和一个 iOS 版本上非常简短测试的结果。我希望它可以跨设备和版本运行,但我还没有完成完整的测试。

    【讨论】:

    • 我不能更改视图的框架
    猜你喜欢
    • 2021-12-20
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    相关资源
    最近更新 更多