Snapkit 与 AutoLayout 优雅布局(一)


本文涉及内容:

1.Autolayout与UIScrollView

2.AutoLayout与UITableViewCell

Autolayout与UIScrollView

这个问题主要是做《仿简书》首页的时候遇到的,当时需要在一个ScrollView里需要放多个大小不固定的Label,发现控件位置总是出错。最后我发现ScrollView相对于普通View存在一些区别:平时我们布局,子视图会依赖父视图来拉约束,但是ScrollViewcontentSize的大小是由其subview的大小来决定的,如果我们子视图继续依赖ScrollView来拉约束,那么就会形成相互依赖,位置无法确定。

那么怎么解决呢?当时的解决方式是:Scrollview里面放一个ContainView,然后子视图拉约束到ContainView,这样ContainView的大小就可以根据子视图来变化,Scrollview的大小根据ContainView来定。

仍然需要遵守的两大原则:

  • scrollView内部子控件的尺寸不能以scrollView的尺寸为参照
  • scrollView内部的子控件的约束必须完整(子控件在水平和垂直方向用约束把ContainView撑满,使containtView扩展以适合它们的尺寸。例如:以前普通布局,只需要定义宽高、左、上的距离即可,但是这时候需要把下、右的距离也补上,不然containView不知道到底尺寸多大)

动手实践:

var topScroll: UIScrollView!
var topContainerView = UIView()

func setTopScroll(){
    topScroll = UIScrollView()
    addSubview(topScroll)
    
    topScroll.snp_makeConstraints { (make) -> Void in
        make.top.equalTo(0)
        make.height.equalTo(topScrollHeight)   //topScrollHeigh为固定值
        make.left.right.equalTo(self)
    }
    topScroll.addSubview(topContainerView)
    
    topContainerView.snp_makeConstraints { (make) -> Void in
        make.edges.equalTo(topScroll)
        make.height.equalTo(topScrollHeight)   //topScrollHeigh为固定值
    }
    
    for idx in 0..<themeArr.count{
        let label = UILabel()
        topContainerView.addSubview(label)

        label.snp_makeConstraints(closure: { (make) -> Void in
                make.height.equalTo(topContainerView)
                if idx > 0, let previousLabel = topScroll.subviews[0].subviews[idx - 1] as? UILabel {
                    make.left.equalTo(previousLabel.snp_right).offset(labelGapX * 2)
                } else {
                    make.left.equalTo(labelGapX)   //labelGapX为固定值
                }
            })
            if idx == themeArr.count - 1 {
                topContainerView.snp_makeConstraints(closure: { (make) -> Void in
                    make.right.equalTo(label)
                })
            }
        }
        
    }
}

上述代码中垂直方向高度为固定,那么水平方向就值得注意,下面这句话代码是关键,可以确定topContainerView的具体大小,进而确定scrollView的大小,也正是符合我们刚阐述的两大原则

topContainerView.snp_makeConstraints(closure: { (make) -> Void in
                make.right.equalTo(label)

AutoLayout与UITableViewCell

我目前遇到的UITableViewCell主要分为三类:

  • UITableviewCell中的子控件大小确定,那么也就是说UITableviewCell的高度、宽度可以确定,这样的cell子控件完全可以依赖UITableviewCell来进行布局。
  • UITableviewCell的高度为可变的。那么我们可以采取上面阐述的方法,子控件依赖ContentView来布局,与ScrollView类似。
  • 第三类是第二类的升级版,UITableviewCell的子控件会根据需要出现或消失

下面主要讲我是怎么处理第三种情况的,示例图如下(简书的简友动态页面):

对于动态UITableViewCell,我们需要让Cell的子控件把约束固定到ContentView上,而且要约束完整。但是简友动态还有一个问题就是高度可变(子View有时候需要隐藏),采取的解决方案是:对约束增加优先级的差异,对单条Constraint进行activedeactive操作,那么意味着可以动态的启用或者禁用某条预置的约束。所以我们只要预先设置一条高优先级的高度为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)
    }

这段代码只是设置了用户名和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约束也要满足“撑满”ContainViewmake.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()
    }
    
}

代码可以进行下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,504评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,898评论 1 300
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,218评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,322评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,693评论 3 290
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,812评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,747评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,476评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,700评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,190评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,541评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,206评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,129评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,903评论 0 199
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,894评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,748评论 2 274

推荐阅读更多精彩内容