iOS 在点击时使用 AutoLayout 展开 UITableViewCell

Posted

技术标签:

【中文标题】iOS 在点击时使用 AutoLayout 展开 UITableViewCell【英文标题】:iOS expand UITableViewCell on click with AutoLayout 【发布时间】:2015-02-16 16:59:25 【问题描述】:

我正在开发简单的应用程序,现在我专注于在用户点击该单元格后扩展 UITableViewCell。这是 ios 8 应用,所以我设置了:

self.tableVIew.rowHeight = UITableViewAutomaticDimension
self.tableVIew.estimatedRowHeight = 50

单元格约束如下所示:

如果用户点击单元格,则调用此函数:

func extend() 
        self.contentView.removeConstraint(self.bottomConstraint)

        let additionalView = UIView()
        additionalView.setTranslatesAutoresizingMaskIntoConstraints(false)
        additionalView.backgroundColor = UIColor.orangeColor()
        self.contentView.addSubview(additionalView)
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[additionalView(50)]-5-|", options: nil, metrics: nil, views: ["additionalView" : additionalView]))
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-5-[additionalView(100)]-5@999-|", options: nil, metrics: nil, views: ["additionalView" : additionalView]))
    

self.bottomConstraint 是绿色圆圈底部和单元格内容视图底部之间的约束。

问题是: 为什么此解决方案仅在在约束中设置了优先级时才有效:

V:|-5-[additionalView(100)]-5@999-|

?

没有明确的优先级我得到了错误:

(
    "<NSLayoutConstraint:0x7a63f7a0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7a737840(60)]>",
    "<NSLayoutConstraint:0x7a644f40 V:|-(5)-[UIView:0x7a63f2a0]   (Names: '|':UITableViewCellContentView:0x7a737840 )>",
    "<NSLayoutConstraint:0x7a644fb0 V:[UIView:0x7a63f2a0(100)]>",
    "<NSLayoutConstraint:0x7a644f70 V:[UIView:0x7a63f2a0]-(5)-|   (Names: '|':UITableViewCellContentView:0x7a737840 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7a644f70 V:[UIView:0x7a63f2a0]-(5)-|   (Names: '|':UITableViewCellContentView:0x7a737840 )>

【问题讨论】:

我的猜测是您当前的单元格高度为 60,新高度为 110,因此需要打破其中一个约束使其增长,默认优先级为 1000,3 个同等优先级约束需要一个被打破。 不应该根据内容视图约束动态计算单元格的高度? 是的,但是 AdditionalView 的高度是 100,不是吗? 是的。也许我没有以正确的方式得到它,但是如果我将高度为 100 且具有约束的视图添加到超级视图,则单元格应该重新计算它的高度,并且没有理由不满足任何约束。 是的,应该的,你可以使用 layoutIfNeeded 来测试更多。 【参考方案1】:

我制作了一个演示,可以为您提供所需的确切行为。 链接在这里: https://github.com/rushisangani/TableViewCellExpand

请按照演示中的说明设置展开/折叠视图的约束。

【讨论】:

谢谢。我知道我可以将优先级设置为 999,它会起作用,但我认为这是一个 hack。 @MichalMoskala 将优先级设置为 999 不是 hack! 还有一件事要提一下细节视图的内部边界约束的优先级必须低于细节视图的高度 你的项目救了我的命!这正是我需要的简单答案类型!不是过度设计的可可豆荚,而是干净直接的东西。【参考方案2】:

'UIView-Encapsulated-Layout-Height' 是在表格视图系统计算出它应该是什么之后创建的行高约束。简单地更改内部约束不足以强制重新计算。

这不是新的意外行为;虽然有时可以通过让单元格超出其 tableview 提供的高度来实现效果,但 table view 数据源委托旨在提供“官方”行高。

Apple 的示例项目Table View Animations and Gestures 具有说明性。它尚未针对 iOS 8 的自动调整单元格进行更新,但无论如何都值得一看。在APLTableViewController.m 中,tableViewController 是单元格俯仰手势的代表,因为它需要调整高度。它的handlePinch: 调用updateForPinchScale: atIndexPath:,它可以按照您的意愿进行扩展。

表格视图控制器不会尝试直接更改行高。首先,它设置自己的自定义数据源对象(称为 sectionInfo)以提供行高的更新值[sectionInfo replaceObjectInRowHeightsAtIndex:indexPath.row withObject:@(newHeight)]; .然后 Table View Controller 执行以下操作:

BOOL animationsEnabled = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
[self.tableView beginUpdates];
[self.tableView endUpdates];
[UIView setAnimationsEnabled:animationsEnabled]; 

关闭所有 UIView 动画是因为这是一个捏,所以它应该立即改变而不会生涩。由于您只想要一次更改,因此您应该尝试不同的动画设置以获得您想要的效果。

它们的关键是一对beginUpdates / endUpdates 调用,显然会触发系统重新计算行高。有可能对于新的 iOS 自动调整单元格,只需更改约束并调用这些方法就足够了;你也可以试试夹reloadRowsAtIndexPaths:withRowAnimation:UITableViewRowAnimationNone

【讨论】:

我正在像这样调用 beginUpdates / endUpdates:func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) let cell = tableView.cellForRowAtIndexPath(indexPath) as TableViewCell cell.extend() tableView.beginUpdates() tableView.endUpdates() 并且布局是正确的,但我收到了第一篇文章中描述的错误。【参考方案3】:

将您的一个视图的高度优先级设置为 999 而不是 1000。

【讨论】:

以上是关于iOS 在点击时使用 AutoLayout 展开 UITableViewCell的主要内容,如果未能解决你的问题,请参考以下文章

iOS 8 AutoLayout 改变视图的位置

iOS Autolayout:处理不同的屏幕高度

按下按钮时自动布局展开标签

iOS -AutoLayout 约束集激活在第二次崩溃

IOS / Storyboard / Autolayout:使Textview垂直扩展以适应文本

AutoLayout如何自动展开标签