仿簡友動態時間軸:使用Snapkit來實現UITableViewCell的動態布局
效果展示:
思路:
前陣子做簡書首頁的時候需要的坑主要是ScrollView與AutoLayout的問題,當時的解決方式是:Scrollview里面放一個ContainView,然后子視圖拉約束到ContainView,這樣ContainView的大小就可以根據子視圖來變化,Scrollview的大小根據ContainView來定。
有兩個特別需要注意點:
1.scrollView內部子控件的尺寸不能以scrollView的尺寸為參照
2.scrollView內部的子控件的約束必須完整(子控件在水平和垂直方向用約束把ContainView撐滿,使containtView擴展以適合它們的尺寸。例如:以前普通布局,只需要定義寬高、左、上的距離即可,但是這時候需要把下、右的距離也補上,不然containView不知道到底尺寸多大)
這里動態UITableViewCell的思路與上面類似,我們需要讓Cell的子控件把約束固定到ContentView上,而且要約束完整。但是簡友動態還有一個問題就是高度可變(子View有時候需要隱藏),采取的解決方案是:對約束增加優先級的差異,對單條Constraint進行active和deactive操作,那么意味著可以動態的啟用或者禁用某條預置的約束。所以我們只要預先設置一條高優先級的高度為0(或者寬度為0)的約束 然后在適當的時候激活它就可以了。
代碼演練:
為了代碼簡介只寫重點部分
sourceUserLabel = UILabel()
sourceUserLabel.sizeToFit()
contentView.addSubview(sourceUserLabel)
sourceUserLabel.snp_makeConstraints { (make) -> Void in
make.top.equalTo(contentView).offset(30)
make.left.equalTo(contentView).offset(20)
}
eventLabel = UILabel()
eventLabel.sizeToFit()
contentView.addSubview(eventLabel)
eventLabel.snp_makeConstraints { (make) -> Void in
make.left.equalTo(sourceUserLabel)
make.top.equalTo(sourceUserLabel.snp_bottom).offset(10)
}</pre>
這段代碼只是設置了用戶名和event類型(發布文字、喜歡之類) ,可以看出來只是設置了左、上的距離,以及SizeToFit,也就是設置了高度和寬度,但是并沒有把ContentView撐滿,繼續
containView = UIView()
containView.backgroundColor = UIColor.redColor()
contentView.addSubview(containView)
containView.snp_makeConstraints { (make) -> Void in
make.top.equalTo(eventLabel.snp_bottom).offset(10)
make.left.equalTo(contentView).offset(10)
make.right.equalTo(contentView).offset(-20)
}
contentLabel = UILabel()
contentLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
contentLabel.font = UIFont.systemFontOfSize(18)
contentLabel.numberOfLines = 3
contentLabel.sizeToFit()
containView.addSubview(contentLabel)
contentLabel.snp_makeConstraints { (make) -> Void in
make.edges.equalTo(containView).inset(UIEdgeInsetsMake(10, 10, 10, 10)).priorityHigh()
}
這個是要把評論內容的Label放到了一個superView中,也就是ContainView中,然后ContainView的尺寸根據內部Label的尺寸來變化,所以Label約束也要滿足“撐滿”ContainView。make.edges.equalTo(containView).inset(UIEdgeInsetsMake(10, 10, 10, 10)).priorityHigh()與SizetoFit結合就可以約束完整,確定ContainView的尺寸。注意PriorityHigh是設置約束優先級為750,默認為1000。
containView.snp_makeConstraints { (make) -> Void in
self.heightContraint = make.height.equalTo(0).constraint
make.bottom.equalTo(contentView).offset(-10)
self.heightContraint?.deactivate()
}
這段代碼有關鍵作用,make.bottom.equalTo(contentView).offset(-10)來達到約束完整的目的,“撐滿”ContentView來確定具體尺寸。同時設置了 self.heightContraint = make.height.equalTo(0).constraint來使containView的告訴為0,約束優先級為1000.那么就是說當此約束activate()的時候,containView高度為零,隱藏。當deactivate()的時候,會使用優先級為750的約束來確定ContainView的高度。
func cellType(bool: Bool){
if bool{
self.heightContraint?.activate()
}
else{
self.heightContraint?.deactivate()
}
}
注:
這個Demo的思路,已經運用到自己的開源項目“仿簡書Github”中,需要的小伙伴可以去下載一起來運行看一下效果。
ScrollView與AutoLayout的闡述放在Here
查閱資料的過程中,也接觸了壓縮阻力(compression resistance)和吸附性約束(hugging constraints)這樣的專業名詞,但是感覺“撐滿”、“完整”這樣的詞語更容易理解所以沒有提及這些名詞,如有不妥,請指正。
有愛的Swift交流群:331527020
希望小手能順便點一下??Star ^_^,朋友的鼓勵和支持是我們繼續分享的動力