约束问题:
阻尼动画(frame、约束)
以新浪微博为例,欢迎界面加载完成后,人物头像从底部移动到上部,并有一个弹簧效果,通过设置约束的方式实现阻尼动画,那么需要调用当前view的layoutIfNeeded()方法才能看到动画效果,如果是frame实现则不需要
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
//只更新了距离父控件上方的距离约束,其他不变
self.headImageView.snp_updateConstraints { (make) in
make.top.equalTo(self.view).offset(100)
}
//更改头像的约束(动画)
UIView.animateWithDuration(2.5, delay: 1.5, usingSpringWithDamping: 0.7, initialSpringVelocity: 0, options: [], animations: {
self.view.layoutIfNeeded()
}) { (finished) in
UIView.animateWithDuration(0.25, animations: {
self.messageLabel.alpha = 1
}, completion: { (finished) in
//切换根控制器
NSNotificationCenter.defaultCenter().postNotificationName("changeTootViewControllerNotification", object:"welcome")
})
}
}
动态行高(frame模型、约束)
以微博为例,将一条微博划分为三部分:原创内容、转发部分和底部工具条(转发、评论和赞),如图:
首先,需要设置tableView的行高相关属性
//tableView相关信息设置
private func setupTableViewInfo() {
//设置自动行高
tableView.rowHeight = UITableViewAutomaticDimension
//预估一个行高,越接近真实越好
tableView.estimatedRowHeight = 200
}
其中绿色部分和蓝色部分是一定会有的,橙色部分为转发内容,可能会有,也可能没有,所以,底部的工具条就需要根据转发内容是否为nil进行判断,判断top的约束对象是原创内容(绿色矩形内)的bottom,还是转发内容(橙色矩形内)的bottom,因为约束参照对象发生了改变,所以在更新约束时,需要先卸载约束,接下来需要为转发内容复制后再更新约束
自定义Cell中的约束设置:
private func setupUI() {
//添加控件
contentView.addSubview(originalView)
contentView.addSubview(retweetView)
contentView.addSubview(toolsView)
//添加约束
originalView.snp_makeConstraints { (make) in
make.left.right.top.equalTo(contentView)
//动态计算行高,因为需要根据原创微博的内容计算高度,所以将原创微博的bottom约束放在了Original内部
}
retweetView.snp_makeConstraints { (make) in
make.top.equalTo(originalView.snp_bottom)
make.left.right.equalTo(contentView)
}
toolsView.snp_makeConstraints { (make) in
//make.top.equalTo(retweetView.snp_bottom)
toolTopContraint = make.top.equalTo(retweetView.snp_bottom).constraint
make.left.right.equalTo(contentView)
make.height.equalTo(35)
}
//设置cell的contentView的约束
contentView.snp_makeConstraints { (make) in
make.top.left.right.equalTo(self)
make.bottom.equalTo(toolsView)
}
}
原创微博内的约束(原创微博的view类中),最后为自身的bottom约束
private func setupUI() {
//添加控件
addSubview(userIconImageView)
addSubview(userNickNameLabel)
addSubview(vipImageView)
addSubview(timeLabel)
addSubview(messageResouceLabel)
addSubview(messageLabel)
addSubview(expiredImageView)
//设置约束
userIconImageView.snp_makeConstraints { (make) in
make.left.top.equalTo(self).offset(margin)
make.size.equalTo(CGSizeMake(35, 35))
}
userNickNameLabel.snp_makeConstraints { (make) in
make.left.equalTo(userIconImageView.snp_right).offset(margin)
make.top.equalTo(userIconImageView)
}
vipImageView.snp_makeConstraints { (make) in
make.left.equalTo(userNickNameLabel.snp_right).offset(margin)
make.centerY.equalTo(userNickNameLabel)
}
timeLabel.snp_makeConstraints { (make) in
make.leading.equalTo(userNickNameLabel)
make.bottom.equalTo(userIconImageView)
}
messageResouceLabel.snp_makeConstraints { (make) in
make.left.equalTo(timeLabel.snp_right).offset(margin)
make.bottom.equalTo(timeLabel)
}
expiredImageView.snp_makeConstraints { (make) in
make.centerY.equalTo(userIconImageView.snp_bottom)
make.centerX.equalTo(userIconImageView.snp_right)
}
messageLabel.snp_makeConstraints { (make) in
make.leading.equalTo(userIconImageView)
make.top.equalTo(userIconImageView.snp_bottom).offset(margin)
}
///原创微博的Bottom约束
self.snp_makeConstraints { (make) in
make.bottom.equalTo(messageLabel).offset(margin)
}
}
转发微博也是一样的方式:
//转发微博设置UI
private func setupUI() {
//添加控件
addSubview(contentLabel)
//添加约束
contentLabel.snp_makeConstraints { (make) in
make.top.left.equalTo(self).offset(margin)
}
self.snp_makeConstraints { (make) in
make.bottom.equalTo(contentLabel).offset(margin)
}
}
因为需要卸载约束,所以需要记录需要更新的那条约束信息
var toolTopContraint: Constraint?//存放底部工具条的top约束
在为Cell中的模型属性复制时,可以第一时间判断到转发微博内是否有数据
如果为nil,就隐藏掉中间的转发微博界面,并更新约束
如果有值,就显示中间的转发微博界面,并更新约束
var statusModel: JSStatusModel?{
didSet{
originalView.userInfo = statusModel//原创微博部分
toolsView.userInfo = statusModel//底部工具条
//更新约束
toolTopContraint?.uninstall() //1.卸载原有约束
if statusModel?.retweeted_status == nil {
retweetView.hidden = true
toolsView.snp_updateConstraints(closure: { (make) in
toolTopContraint = make.top.equalTo(originalView.snp_bottom).constraint
})
}else {
retweetView.userInfo = statusModel//需要先赋值后更新约束,才能动态决定行高
retweetView.hidden = false
toolsView.snp_updateConstraints(closure: { (make) in
toolTopContraint = make.top.equalTo(retweetView.snp_bottom).constraint
})
}
}
}
更新约束总结:
如果通过约束实现动画,需要调用当前view的layoutIfNeeded()方法
如果更新约束时参照的对象发生了改变,需要先卸载约束
如果没有卸载约束,需要使用update,不能使用make
如果已经卸载了约束,重新设置约束时,使用make和update一样