ios - 如何解决我的 UICollectionView 的 "removeConstraint() not working"问题?

标签 ios swift nslayoutconstraint

以编程方式(没有 Storyboard),我试图删除一组约束并在设备旋转时创建一组新约束。我用来删除约束的代码执行时没有错误,但实际上并没有删除约束。当添加新的(冲突的)约束集时,这会导致布局错误。

我正在使用没有 Storyboard的 Xcode 10.1 和 Swift 4.2。在我的 MainViewController 中,我通过 viewDidLoad() 调用的函数创建并放置了一个名为“ticketsView”的 UICollectionView。在 addChild()addSubview() 之后,我调用一个名为 applyTicketsViewConstraints() 的函数来确定设备的当前方向,然后(是预期)删除任何现有约束并为当前设备方向应用适当的约束集。

我重写了 viewWillTransition:toSize:withCoordinator(),它会在设备旋转时从协调器闭包中调用相同的 applyTicketsViewConstraints() 函数。

在应用程序启动时,约束会根据初始设备方向正确应用。设备第一次旋转 90 度时,显示也成功改变,但之后的任何旋转都会导致“[LayoutConstraints] 无法同时满足约束”错误消息。

我试过遍历现有的 ticketsView 约束并一次移除一个约束,我也试过一次全部移除它们 - 但两种方法都不会导致约束的实际移除。它们似乎都运行成功,但约束在它们完成后仍然存在。

    func createTicketCollectionWindow() {
        ticketsLayout = UICollectionViewFlowLayout()
        ticketsVC = TicketCollectionController(collectionViewLayout: ticketsLayout)
        ticketsVC?.collectionView?.backgroundColor = UIColor.darkGray
        ticketsView = ticketsVC!.view
        ticketsView.translatesAutoresizingMaskIntoConstraints = false
        addChild(ticketsVC!)
        self.view.addSubview(ticketsView)
        applyTicketsViewConstraints()
    }
    func applyTicketsViewConstraints() {
        let safe = self.view.safeAreaLayoutGuide
        let deviceSize = UIScreen.main.bounds.size
        for individualConstraint in ticketsView.constraints {
            print("TicketViewConstraints:   Removing Constraint: \(individualConstraint)" )
            // ticketsView.removeConstraint(individualConstraint)
        }
        ticketsView.removeConstraints(ticketsView.constraints)
        // self.view.removeConstraints(ticketsView.constraints)
        if deviceSize.width < deviceSize.height {
            print("TicketsView Constraint:  Device is in PORTRAIT orientation!")
            ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width).isActive = true
            ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 ).isActive = true
            ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0).isActive = true
            ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.75).isActive = true
        } else {
            print("TicketsView Constraint:  Device is in LANDSCAPE orientation!")
            ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width).isActive = true
            ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 ).isActive = true
            ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0).isActive = true
            ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.65).isActive = true
        }
        ticketsView.layoutIfNeeded()
    }
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        coordinator.animate(alongsideTransition: { (_) in
            self.applyTicketsViewConstraints()
            self.ticketsVC?.collectionView.reloadData()
        }) { (_) in
            self.ticketsView.layoutIfNeeded()
        }
    }

我希望我在上面的代码中创建的 4 个约束将被删除,以便我可以使用不同的值重新创建它们。我似乎找不到删除它们的方法(有效)。上面代码中注释掉的上面两行是为了表明我也尝试过(不成功)。

最佳答案

你可以试试

var portrait = [NSLayoutConstraint]()
var landscape = [NSLayoutConstraint]()

let porCon1  = ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width) 
let porCon2  =  ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 ) 
let porCon3  = ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0) 
let porCon4  = ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.75) 

portrait = [porCon1,porCon2,porCon3,porCon4]

let landCon1  = ticketsView.leadingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -safe.layoutFrame.width) 
let landCon1  = ticketsView.trailingAnchor.constraint(equalTo:safe.trailingAnchor, constant: 0 ) 
let landCon1  = ticketsView.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: 0) 
let landCon1  = ticketsView.heightAnchor.constraint(equalToConstant: safe.layoutFrame.height * 0.65) 

landscape = [landCon1,landCon2,landCo3,landCon4]

func setPortrait(_ por:Bool) {  
    portrait.forEach { $0.isActive = por }
    landscape.forEach { $0.isActive = !por } 
}

也可以

NSLayoutConstraint.deActivate(portrait)
NSLayoutConstraint.deActivate(landscape)
if por {
   NSLayoutConstraint.activate(portrait)
}
else { 
  NSLayoutConstraint.activate(landscape)
}

关于ios - 如何解决我的 UICollectionView 的 "removeConstraint() not working"问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55554323/

相关文章:

validation - 有没有办法将多个值传递给 rangeOfString?

ios - 更新到 XCode 6.3 (Swift 1.2) 后出现 "Objective-C method conflicts with optional requirement method"错误

ios - 以编程方式添加约束给我错误

ios - 如何让 UITextField 根据所使用的 iPhone 适当调整其大小?

ios - UICollectionView 显示隐藏动画问题

objective-c - EventKit:提醒 dueDateComponents 与 Alarm

swift - 创建一个带有不允许转义函数的参数的 Swift 函数?

swift - 将 func loadview 中声明的 self.view 约束到 View Controller 的部分区域

iOS XMPP 框架与 Openfire Server 获取所有注册用户

android - Cordova 后台地理定位支持,应用程序不会在一段时间后终止