Swift:出现了神秘的约束

Posted

技术标签:

【中文标题】Swift:出现了神秘的约束【英文标题】:Swift: Mysterious constraint appearing 【发布时间】:2017-02-13 18:50:57 【问题描述】:

我正在尝试在 UICollectionView 中创建警报列表,其中“开启”警报具有图像 (alarmImg) 和时间标签 (alarmLbl),而“关闭”警报具有图像和空白时间标签。我希望“关闭”警报图像居中,而“开启”警报图像有一个偏移量以说明标签。

这是我在cellForItemAtIndexPath 中的代码,其中 cell 是一个出队的 cell,alarmLbls 是一个闹钟时间的字符串数组。

cell.alarmLbl.text = alarmLbls[indexPath.row]     

if alarmLbls[indexPath.row] == "" 
    cell.alarmImg.image = UIImage(named: "alarm_off")
    let alarmImgYConstraintOff = NSLayoutConstraint(item: cell.alarmImg, attribute: .CenterY, relatedBy: .Equal, toItem: cell.mainView, attribute: .CenterY, multiplier: 1, constant: 0)
    alarmImgYConstraintOff.active = true
    cell.layoutIfNeeded()

else 
    cell.alarmImg.image = UIImage(named: "alarm_on")
    let alarmImgYConstraintOn = NSLayoutConstraint(item: cell.alarmImg, attribute: .CenterY, relatedBy: .Equal, toItem: cell.mainView, attribute: .CenterY, multiplier: 0.75, constant: 0)
    alarmImgYConstraintOn.active = true
    cell.layoutIfNeeded()

初始布局看起来不错,但是当我在包含“on”警报的单元格上调用 reloadItemsAtIndexPaths 时,我收到一个约束错误,指示正在应用“off”约束,在这种情况下,“on”约束中断并且图像向中心移动。不过,根据打印测试,第一个 if 块似乎没有被这些单元格调用(仅适用于从屏幕外重新加载的“关闭”单元格),这是我设置这些约束的唯一地方.

我几乎尝试了所有我能想到的解决方案迭代:

    强制alarmImgYConstraintOff.active = false 通过 IB 设置中心约束并以编程方式将其关闭 将“on”块切换到if 语句 将else 更改为else if

将“on”约束的优先级设置为高于“off”约束的优先级只会使所有“off”图像在重新加载时向上移动。但是,由于某种原因,在第四次重新加载时,图像会移回其原始居中(正确)位置。

关于我在这里做错了什么有什么想法吗?

编辑:关闭不需要的约束的代码

cell.alarmLbl.text = alarmLbls[indexPath.row]

let alarmImgYConstraintOff = NSLayoutConstraint(item: cell.alarmImg, attribute: .CenterY, relatedBy: .Equal, toItem: cell.mainView, attribute: .CenterY, multiplier: 1, constant: 0) 
let alarmImgYConstraintOn = NSLayoutConstraint(item: cell.alarmImg, attribute: .CenterY, relatedBy: .Equal, toItem: cell.mainView, attribute: .CenterY, multiplier: 0.75, constant: 0)    

if alarmLbls[indexPath.row] == "" 
    cell.alarmImg.image = UIImage(named: "alarm_off")
    alarmImgYConstraintOn.active = false
    alarmImgYConstraintOff.active = true
    cell.layoutIfNeeded()

else 
    cell.alarmImg.image = UIImage(named: "alarm_on")
    alarmImgYConstraintOff.active = false
    alarmImgYConstraintOn.active = true
    cell.layoutIfNeeded()

初始布局看起来不错,和以前一样,但是一旦我重新加载“打开”单元格(保存第一次重新加载),布局仍然会中断。例如。 “on”单元格的第二次重新加载中断,所有“on”和“off”单元格的后续重新加载也是如此(尽管“off”单元格没有明显差异);但是,如果我先重新加载“关闭”单元格,则在重新加载“开启”单元格之前不会有任何中断。

【问题讨论】:

当您打开一个约束时,您应该关闭另一个。如果您尝试过但它不起作用,那么您可能没有正确执行。您可以发布该尝试的代码吗? 已编辑问题以包含新代码和结果!不幸的是,仍然没有骰子。 【参考方案1】:

当您设置alarmImgYConstraintOff.active = true 时,您只是在已有的基础上添加了第二个约束。在应用新约束之前先尝试删除不需要的约束。这应该可以解决问题。

【讨论】:

我已经根据您的建议发布了我的代码,但我仍然看到问题(请参阅编辑后的问题)。 我最近在我的应用程序中做了一个类似的事情,涉及移动视图。我通过更改 constraint.constant 的值而不是添加和删除约束来做到这一点,并且没有任何问题。也许试试看? 我刚刚尝试了一个约束,在“off”块中设置 .constant = 0,在“on”块中设置 -10。 “打开”单元格重新加载布局中断,但图像仍保留在应有的位置。 “关闭”单元格重新加载布局中断,将它们移动到 -10 位置。一旦我重新加载“打开”单元格,问题似乎又开始了。不过有趣的是,对于一个(但不是全部)“关闭”单元格,图像会在第四次重新加载时移回正确的位置?【参考方案2】:

尝试保存对同一约束的引用并将 .multiplier 更改为 1 或 0.75,无需更改整个约束即可更改它。

【讨论】:

看起来约束乘数是只读属性,所以你不能通过将 .multiplier 设置为不同的值来修改它们。

以上是关于Swift:出现了神秘的约束的主要内容,如果未能解决你的问题,请参考以下文章

Swift 包中的 XIB 文件 - 忽略约束

Swift - 以编程方式刷新约束

Swift编程约束下边距不起作用

swift 自定义view VFL 设置约束冲突

UITableView 自动调整行约束在 iPhone 6Plus 上神秘地打破

在 Swift 运行时更改自动布局约束的 UIView 的框架