仿簡友動態時間軸:使用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 inmake.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 ^_^,朋友的鼓勵和支持是我們繼續分享的動力