Swift - 编程方式刷新约束

5

我的VC以附有“将 stackView 与“对齐底部到安全区域”一起开始。

我有一个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的出现。

正如我所提及的,在选项卡之间切换可解决此问题,因此一些代码在切换后执行以检测tabBar。 有人知道这个代码吗? 我尝试调用 viewDidLayoutSubviews viewWillLayoutSubviews 方法都没有成功...有任何建议吗?


当您显示选项卡栏时,您将需要创建一个底部对齐的插座并更改其常量值。 - Anil Arigela
不要使用这种方法。我想刷新约束条件。 - Bogdan Bogdanov
你的 tabBar 是添加到视图中的对象吗?还是你的 VC 是 UITabBarController 的一个选项卡,但是标签栏被隐藏了?或者,你的 VC 嵌入在导航控制器中,并将底部栏称为 tabBar - DonMag
UITabBarController是主控制器,而在tabBar的索引0上是stackView。 - Bogdan Bogdanov
4个回答

3
这种业余的方法解决了我的错误... :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()

}

这可能是一种黑客行为,但实际上它确实运行得非常好! - Michael

0

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


0

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

stackView.superview?.layoutIfNeeded()

2
他没有更新约束...他只是希望他的堆栈能够随着选项卡栏的显示和隐藏而调整。 - Jawad Ali
没关系,我会花一些声望作为赏金,然后一些专业人士会回答这个问题:D - Bogdan Bogdanov

-1

苹果的 Human Interface Guidelines 指出,不应该对选项卡栏进行操作,这就是为什么(我猜测)设置 tabBar.isHidden 不能正确地更新其余的视图层次结构。

快速搜索会出现各种 UITabBarController 扩展程序,用于显示/隐藏选项卡栏...但它们似乎都将 tabBar 推到屏幕下方,而不是设置其 .isHidden 属性。可能适合您的使用,也可能不适合。

我假设根据您的评论,您在选项卡索引 0 中的 VC 上有一个按钮(或其他操作)来显示/隐藏选项卡栏?

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

在您的项目中添加此 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 版本上进行非常简短测试的结果。我期望它可以跨设备和版本工作,但我没有进行完整的测试。


我不能改变视图的框架,这不是我的选择。 - Bogdan Bogdanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接