返回 导航

Swift

hangge.com

Swift - UIStackView使用详解2(Stack View嵌套使用、伸缩优先级)

作者:hangge | 2017-08-16 08:10
在之前的文章中,我简单地演示了如何使用 Stack View 进行布局。本文接着通过样例演示如何通过 Stack View 嵌套 Stack View 来实现更加复杂的页面布局。

三、Stack View 嵌套布局样例

1,效果图

(1)我们首先使用 Horizontal Stack View 将单元格内部分成左中右三个区域,左侧放置电影海报,右侧放置按钮。
(2)中间区域嵌套了一个 Vertical Stack View,其内部分为上下两部分,分别用来显示电影名称和简介。

2,实现步骤

(1)首先打开 Storyboard,删掉当前的 ViewController 视图。重新拖入 TableViewController 视图,并将其设置为 Initial View Controller,然后内嵌一个导航控制器。

(2)创建一个自定义类 MyTableViewController(继承自 UITableViewController)。并将 StoryBoard 中的 TableViewController 与这个新建类进行绑定。

(3)创建一个自定义类 MyTableViewCell(继承自 UITableViewCell)。并将 StoryBoard 中的单元格与这个新建类进行绑定。

(4)给单元格设置一个标示符 myCell

(5)在单元格中,从左到右分别拖入一个 Image ViewVertical ViewView。它们的位置尺寸可以先不管。

(6)我们将 Image View Content Mode 设置为 Apect Fill,同时勾选上 Clip To Bounds

(7)将中间的 Stack ViewSapcing 设为 5,其它属性值保持默认的即可。

(8)选中这三个新添加的视图,然后点击右下角的 Stack 按钮,这三个视图便自动组合成了一个 Stack View

(9)选中这个新建 Stack View,设置其约束(距上下左右 5pt)。同时在其属性编辑窗口中,设置子元件的间距为 15,分布比例、对齐方式都为 Fill

(10)给 Image View 添加个宽高比约束,约束值为 2:3

(11)给最后一个 View 添加个宽度约束,值为 45。这样中间的 Vertical Stack 就占用了剩下的空间。

(12)在最后一个 View 中添加一个 Button,并设置好其属性和相关约束(高度 25,左右边距 0,垂直居中)

(13)往中间的 Stack View 中分别拖入一个 Label 和一个 Text View,并设置好它们的属性样式。(如果 Label 被挤不见了,拖动一下 Text View 上边框就好了)

(14)最后将 ImageViewLabelTextView 在对应的 MyTableViewCell 类中做 IBOutlet 关联引用。MyTableViewCell 完整代码如下:
import UIKit

class MyTableViewCell: UITableViewCell {
    
    //海报
    @IBOutlet weak var poster: UIImageView!
    //标题
    @IBOutlet weak var title: UILabel!
    //简介
    @IBOutlet weak var introduction: UITextView!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        //去除TextView的内边距
        introduction.textContainerInset = .zero
        introduction.contentInset = UIEdgeInsetsMake(0, -5, 0, 0)
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
}

(15)表格视图控制器 MyTableViewController 代码如下:
import UIKit

class MyTableViewController: UITableViewController {
    
    //表格数据
    let Movies = [Movie(poster:"p2455156816.jpg", title: "记忆大师",
                        introduction: "导演: 陈正道\n编剧: 任鹏 / 陈正道\n"
                            + "主演: 黄渤 / 段奕宏 / 徐静蕾 / 杨子姗 / 梁杰理"),
                  Movie(poster:"p2493595992.jpg", title: "三个老枪手",
                        introduction: "导演: 扎克·布拉夫\n编剧: 西奥多·梅尔菲\n"
                            + "主演: 迈克尔·凯恩 / 摩根·弗里曼 / 艾伦·阿金 / 乔伊·金"),
                  Movie(poster:"p2453433569.jpg", title: "亚瑟王:斗兽争霸",
                        introduction: "导演: 盖·里奇\n编剧: 卓比·哈罗德 / 盖·里奇\n"
                            + "主演: 查理·汉纳姆 / 裘德·洛 / 阿斯特丽德·伯格斯-弗瑞斯贝"),
                  Movie(poster:"p2460006593.jpg", title: "神奇女侠",
                        introduction: "导演: 派蒂·杰金斯\n编剧: 艾伦·海因伯格\n"
                            + "主演: 盖尔·加朵 / 克里斯·派恩 / 康妮·尼尔森 / 罗宾·怀特")]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    //返回分区数
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    //返回单元格数
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)
        -> Int {
        return Movies.count
    }

    //返回单元格
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
        //获取单元格
        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
            as! MyTableViewCell
        
        //设置单元格数据
        let movie = Movies[indexPath.row]
        cell.poster.image = UIImage(named: movie.poster)
        cell.title.text = movie.title
        cell.introduction.text = movie.introduction

        return cell
    }
}

//电影信息
struct Movie {
    var poster:String //海报
    var title:String  //标题
    var introduction:String //简介
}
源码下载hangge_1750.zip

四、拉伸、压缩优先级设置

1,现象描述

(1)假设我们需要实现如下列表,左侧显示文章标题,右侧显示日期。

(2)如果使用 Horizontal Stack View 布局的话,只需将两个 Label 添加到其内部即可。

(3)但添加完会发现系统提示有约束错误:

(4)而程序运行后的效果如下,与我们想要的效果不一样。

2,问题原因

由于默认情况下,两个 UILabel 的抗压缩优先级都是一样的(750),而有时单元格的空间会不足以完全显示出标题和日期内容,这时系统就不知道该压缩哪个 Label 的宽度。

3,解决办法

(1)我们希望在空间不足的情况下,优先压缩标题 Label 的宽度,那么可以将其抗压缩优先级调低,改成:749
(2)而在空间充足的情况下,同样优先拉伸标题 Label 的宽度,那么同样将其抗拉伸优先级调低,改成:250

(3)再次运行程序,便发现列表内容显示正常了。
评论

全部评论(0)

回到顶部