仿简友动态时间轴:使用Snapkit来实现UITableViewCell的动态布局
jopen
9年前
<h3>效果展示:</h3> <div class="image-package" href="https://simg.open-open.com/show/3b054d0a1caf0b6409078ce6785b228f.png"> <img src="https://simg.open-open.com/show/3b054d0a1caf0b6409078ce6785b228f.png" width="281" height="522" data-original-src="https://simg.open-open.com/show/44a080677e966f4ebf7cac74bd7888fd.png" /> <br /> <div class="image-caption"> 简书 </div> </div> <h3>思路:</h3> <p>前阵子做简书首页的时候需要的坑主要是<code>ScrollView</code>与<code>AutoLayout</code>的问题,当时的解决方式是:<code>Scrollview</code>里面放一个<code>ContainView</code>,然后子视图拉约束到<code>ContainView</code>,这样<code>ContainView</code>的大小就可以根据子视图来变化,<code>Scrollview</code>的大小根据<code>ContainView</code>来定。</p> <p><strong>有两个特别需要注意点:</strong><br /> 1.<code>scrollView</code>内部子控件的尺寸不能以<code>scrollView</code>的尺寸为参照<br /> 2.<code>scrollView</code>内部的子控件的约束必须完整(子控件在水平和垂直方向用约束把<code>ContainView</code>撑满,使<code>containtView</code>扩展以适合它们的尺寸。例如:以前普通布局,只需要定义宽高、左、上的距离即可,但是这时候需要把下、右的距离也补上,不然<code>containView</code>不知道到底尺寸多大)</p> <div class="image-package" href="https://simg.open-open.com/show/ba51ff30335d95a9c4d623f9aa097128.png"> <img src="https://simg.open-open.com/show/ba51ff30335d95a9c4d623f9aa097128.png" width="375" height="248" data-original-src="https://simg.open-open.com/show/edbe408fcd7e198639703e8aa1160ce5.png" /> <br /> <div class="image-caption"> Cell分析 </div> </div> <p><br /> 这里动态<code>UITableViewCell</code>的思路与上面类似,我们需要让<code>Cell</code>的子控件把约束固定到<code>ContentView</code>上,而且要约束完整。但是简友动态还有一个问题就是高度可变(子<code>View</code>有时候需要隐藏),采取的解决方案是:对约束增加优先级的差异,对单条<code>Constraint</code>进行<code>active</code>和<code>deactive</code>操作,那么意味着可以动态的启用或者禁用某条预置的约束。所以我们只要预先设置一条高优先级的高度为0(或者宽度为0)的约束 然后在适当的时候激活它就可以了。</p> <h3>代码演练:</h3> <p>为了代码简介只写重点部分</p> <pre class="brush:java; toolbar: true; auto-links: false;"> 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> <p>这段代码只是设置了用户名和event类型(发布文字、喜欢之类) ,可以看出来只是设置了左、上的距离,以及<code>SizeToFit</code>,也就是设置了高度和宽度,但是并没有把<code>ContentView</code>撑满,继续</p> <pre class="brush:java; toolbar: true; auto-links: false;"> 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() }</pre> <p>这个是要把评论内容的Label放到了一个<code>superView</code>中,也就是<code>ContainView</code>中,然后ContainView的尺寸根据内部<code>Label</code>的尺寸来变化,所以Label约束也要满足“撑满”ContainView。<code>make.edges.equalTo(containView).inset(UIEdgeInsetsMake(10, 10, 10, 10)).priorityHigh()</code>与<code>SizetoFit</code>结合就可以约束完整,确定ContainView的尺寸。注意<code>PriorityHigh</code>是设置约束优先级为750,默认为1000。</p> <pre class="brush:java; toolbar: true; auto-links: false;"> containView.snp_makeConstraints { (make) -> Void in self.heightContraint = make.height.equalTo(0).constraint make.bottom.equalTo(contentView).offset(-10) self.heightContraint?.deactivate() }</pre> <p>这段代码有关键作用,<code>make.bottom.equalTo(contentView).offset(-10)</code>来达到约束完整的目的,“撑满”<code>ContentView</code>来确定具体尺寸。同时设置了 <code>self.heightContraint = make.height.equalTo(0).constraint</code>来使<code>containView</code>的告诉为0,约束优先级为1000.那么就是说当此约束<code>activate()</code>的时候,<code>containView</code>高度为零,隐藏。当<code>deactivate()</code>的时候,会使用优先级为750的约束来确定<code>ContainView</code>的高度。</p> <pre class="brush:java; toolbar: true; auto-links: false;"> func cellType(bool: Bool){ if bool{ self.heightContraint?.activate() } else{ self.heightContraint?.deactivate() } }</pre> <h3>注:</h3> <p>这个Demo的思路,已经运用到自己的开源项目<a href="/misc/goto?guid=4959652236334368881" target="_blank">“仿简书Github”</a>中,需要的小伙伴可以去下载一起来运行看一下效果。<br /> <code>ScrollView</code>与<code>AutoLayout</code>的阐述放在<a href="/misc/goto?guid=4959652236430351541" target="_blank">Here</a><br /> 查阅资料的过程中,也接触了压缩阻力(compression resistance)和吸附性约束(hugging constraints)这样的专业名词,但是感觉“撑满”、“完整”这样的词语更容易理解所以没有提及这些名词,如有不妥,请指正。</p> <p>有爱的Swift交流群:331527020<br /> <strong>希望小手能顺便点一下⭐️Star ^_^,朋友的鼓励和支持是我们继续分享的动力</strong></p> <p>来自: <a href="/misc/goto?guid=4959652236511332036" rel="nofollow" target="_blank">http://www.jianshu.com/p/3429ac5a4e4d</a></p>