约束相关(阻尼动画,Cell自动行高,约束更新)

约束问题:

阻尼动画(frame、约束)

以新浪微博为例,欢迎界面加载完成后,人物头像从底部移动到上部,并有一个弹簧效果,通过设置约束的方式实现阻尼动画,那么需要调用当前view的layoutIfNeeded()方法才能看到动画效果,如果是frame实现则不需要

约束相关(阻尼动画,Cell自动行高,约束更新)_第1张图片
animation.png
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模型、约束)

以微博为例,将一条微博划分为三部分:原创内容、转发部分和底部工具条(转发、评论和赞),如图:

约束相关(阻尼动画,Cell自动行高,约束更新)_第2张图片
weibo_home.png

首先,需要设置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一样

你可能感兴趣的:(约束相关(阻尼动画,Cell自动行高,约束更新))