仿简友动态时间轴:使用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>