Swift - Programmatically refresh constraints

旧时模样 提交于 2021-02-10 06:15:22

问题


My VC starts with stackView attached with Align Bottom to Safe Area .

I have tabBar, but in the beginning is hidden tabBar.isHidden = true.

Later when the tabBar appears, it hides the stackView

So I need function that refresh constraints after tabBar.isHidden = false


When I start the app with tabBar.isHidden = false the stackView is shown properly.


Tried with every function like: stackView.needsUpdateConstraints() , updateConstraints() , setNeedsUpdateConstraints() without success.


Now I'm changing the bottom programatically, but when I switch the tabBarIndex and return to that one with changed bottom constraints it detects the tabBar and lifts the stackView under another view (which is not attached with constraints). Like is refreshing again the constraints. I'm hiding and showing this stackView with constrains on/off screen.

I need to refresh constraints after tabBar.isHidden = false, but the constraints don't detect the appearance of the tabBar.

As I mention switching between tabBars fixes the issue, so some code executes to detecting tabBar after the switch. Is anyone know this code? I tried with calling the methods viewDidLayoutSubviews and viewWillLayoutSubviews without success... Any suggestions?


回答1:


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

This amateur approach fixed my bug... :D




回答2:


If you want to update view's layout, you can try layoutIfNeeded() function.




回答3:


after updating stackView constraints call this method:

stackView.superview?.layoutIfNeeded()



回答4:


Apple's Human Interface Guidelines indicate that one should not mess around with the Tab Bar, which is why (I'm guessing) setting tabBar.isHidden doesn't properly update the rest of the view hierarchy.

Quick searching comes up with various UITabBarController extensions for showing / hiding the tab bar... but they all appear to push the tabBar down off-screen, rather than setting its .isHidden property. May or may not be suitable for your use.

I'm assuming from your comments that your VC in tab index 0 has a button (or some other action) to show / hide the tabBar?

If so, here is an approach that may do the job....

Add this enum in your project:

enum TabBarState {
    case toggle, show, hide
}

and put this func in that view controller:

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
    }
}

You can call it with:

// 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)

I would expect that simply pairing .setNeedsLayout() with .layoutIfNeeded() after setting the tabBar's .isHidden property should do the job, but apparently not.

The quick frame height change (combined with .setNeedsLayout()) does trigger auto-layout, though, and the height change is not visible.

NOTE: This is the result of very brief testing, on one device and one iOS version. I expect it will work across devices and versions, but I have not done complete testing.



来源:https://stackoverflow.com/questions/60526419/swift-programmatically-refresh-constraints

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!