在约束上动画更改 UITableView 节标题的高度
Posted
技术标签:
【中文标题】在约束上动画更改 UITableView 节标题的高度【英文标题】:Animate changing height of a UITableView section header on constraints 【发布时间】:2015-05-04 07:34:49 【问题描述】:我有一个自定义 UIView 用作 UITableView 的部分标题。我希望能够通过更改标题视图的高度来展开和折叠标题视图并为该更改设置动画。
标题视图包含两个使用约束布局的标签。当视图折叠时,放置在底部的标签的高度约束将设置为 0。
当我按下折叠/展开按钮时,我更改了由tableView:heightForHeaderInSection:
返回的headerHeight
变量。这里我也改变了高度约束的值。我在tableView.beginUpdates()
和tableView.endUpdates()
中都这样做,但标题视图不会动画。在我开始滚动表格视图之前,它甚至不会使用新的高度。或者,我使用tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Automatic)
,它会为标题视图的高度设置动画,但会弄乱其中的子视图(顶部标签会在整个标题视图中垂直拉伸,即使它具有固定高度)。
有没有人有一个解决方案,可以使用约束正确地动画标题视图高度和它的子视图?
下面是HeaderView的代码:
class HeaderView: UIView
let titleLabel = UILabel()
let subtitleLabel = UILabel()
let expandButton = UIButton()
var subtitleLabelHeightConstraint: NSLayoutConstraint!
init()
super.init(frame: CGRectNull)
titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
subtitleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
expandButton.setTranslatesAutoresizingMaskIntoConstraints(false)
expandButton.setTitle("Expand / Collapse", forState: .Normal)
addSubview(titleLabel)
addSubview(subtitleLabel)
addSubview(expandButton)
let views = ["titleLabel": titleLabel, "subtitleLabel": subtitleLabel, "expandButton": expandButton]
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[titleLabel]-[expandButton]|", options: nil, metrics: nil, views: views))
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[subtitleLabel]|", options: nil, metrics: nil, views: views))
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-20-[titleLabel]-(>=0)-|", options: nil, metrics: nil, views: views))
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(>=0)-[subtitleLabel]|", options: nil, metrics: nil, views: views))
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-20-[expandButton]-(>=0)-|", options: nil, metrics: nil, views: views))
titleLabel.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 20))
subtitleLabelHeightConstraint = NSLayoutConstraint(item: subtitleLabel, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 20)
subtitleLabel.addConstraint(subtitleLabelHeightConstraint)
required init(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
还有TableViewController
的代码:
class TableViewController: UITableViewController
let headerView: HeaderView =
let view = HeaderView()
view.titleLabel.text = "Title"
view.subtitleLabel.text = "Subtitle"
view.backgroundColor = UIColor.lightGrayColor()
return view
()
var headerHeight: CGFloat = 60
override func viewDidLoad()
super.viewDidLoad()
headerView.expandButton.addTarget(self, action: "toggleExpansion", forControlEvents: .TouchUpInside)
func toggleExpansion()
tableView.beginUpdates()
if headerHeight == 60
headerHeight = 40
headerView.subtitleLabelHeightConstraint.constant = 0
else
headerHeight = 60
headerView.subtitleLabelHeightConstraint.constant = 20
tableView.endUpdates()
// Alternatively use tableView.reloadSections instead of begin and end updates:
// tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Automatic)
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
return 1
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 2
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = "Cell"
return cell
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
return headerHeight
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
return headerView
我还使用代码在https://github.com/lammertw/DynamicSectionHeader 创建了一个项目。
【问题讨论】:
问题解决了吗?我现在正在经历这种情况。我觉得我很近,但很远。我尝试了各种各样的事情,包括动画布局约束。没运气。我必须滚动才能看到更改。 我已经记录了这一点。 youtu.be/bcH5djtYYXo 我找到了解决这个问题的方法,尽管它是一种解决方法,可能不适合您的目的:horseshoe7.wordpress.com/2016/03/17/… 您可以使用 UIView.Animate 块和调用 layoutifneeded mathod 为您更改设置动画 【参考方案1】:尝试替换这个:
func toggleExpansion()
tableView.beginUpdates()
if headerHeight == 60
headerHeight = 40
headerView.subtitleLabelHeightConstraint.constant = 0
else
headerHeight = 60
headerView.subtitleLabelHeightConstraint.constant = 20
tableView.endUpdates()
// Alternatively use tableView.reloadSections instead of begin and end updates:
// tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Automatic)
通过这个:
func toggleExpansion()
if headerHeight == 60
headerHeight = 40
headerView.subtitleLabelHeightConstraint.constant = 0
else
headerHeight = 60
headerView.subtitleLabelHeightConstraint.constant = 20
tableView.beginUpdates()
tableView.endUpdates()
// Alternatively use tableView.reloadSections instead of begin and end updates:
// tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Automatic)
【讨论】:
以上是关于在约束上动画更改 UITableView 节标题的高度的主要内容,如果未能解决你的问题,请参考以下文章
如何在 UITableView 中为节标题的高度变化设置动画?
动画 UITableView 的自动布局顶部约束导致崩溃,有啥线索吗?