[Swift通天遁地]二、表格表单-(3)在表格中嵌套另一个表格并使Cell的高度自适应

时间:2022-11-23 17:09:30

本文将演示如何在表格中嵌套另一个表格并使Cell的高度自适应,创建更加强大的布局效果。

在项目文件夹【DemoApp】上点击鼠标右键,弹出右键菜单。

【New File】->【Cocoa Touch Class】->【Next】->

【Class】:CustomizeUITableViewCell ,类名。

【Subclass of】:UITableViewCell ,父类

【Language】:Swift

->【Next】->【Create】
在项目导航区,打开刚刚创建的代码文件【CustomizeUITableViewCell.swift】

现在开始编写代码,创建一个自定义的单元格的类。

  1 import UIKit
  2 
  3 //引入需要遵循的表格视图的相关协议UITableViewDataSource, UITableViewDelegate
  4 class CustomizeUITableViewCell: UITableViewCell, UITableViewDataSource, UITableViewDelegate {
  5     
  6     //添加两个属性:
  7     //1.表格对象
  8     var tableView : UITableView!;
  9     //2.数据来源
 10     var comments : [String] = []
 11     
 12     //重写单元格的初始化方法,在该方法中对单元格进行自定义操作
 13     override init(style: UITableViewCellStyle, reuseIdentifier: String?)
 14     {
 15         //首先实现父类的初始化方法
 16         super.init(style: style, reuseIdentifier: reuseIdentifier);
 17         
 18         //初始化一个表格对象,并设置表格对象的显示区域
 19         tableView = UITableView(frame: CGRect(x: 20, y: 0, width: 280, height: 90))
 20         //设置表格对象的数据源为当前的视图控制器对象
 21         tableView.dataSource = self
 22         //设置表格对象的代理为当前的视图控制器对象
 23         tableView.delegate = self
 24         //设置不允许内部表格的滚动,
 25         //只允许单元格所属表格可以进行滚动
 26         tableView.isScrollEnabled = false;
 27         
 28         //将表格视图添加到根视图中
 29         self.addSubview(tableView)
 30     }
 31     
 32     //添加一个代理方法,用来设置表格的行数
 33     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
 34     {
 35         //在此设置表格的行数,与数组的长度保持一致
 36         return comments.count
 37     }
 38     
 39     //添加一个代理方法,用来初始化或复用表格中的单元格
 40     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
 41     {
 42         //创建一个字符串常量,作为单元格的复用标识
 43         let identifier = "reusedCell"
 44         //根据复用标识,从表格中获得可以复用的单元格
 45         var cell = tableView.dequeueReusableCell(withIdentifier: identifier)
 46         
 47         //如果没有可以复用的单元格
 48         if(cell == nil)
 49         {
 50             //则初始化一个默认样式的单元格,并设置单元格的复用标识
 51             cell = UITableViewCell(style: UITableViewCellStyle.default,
 52                                    reuseIdentifier: identifier)
 53         }
 54         
 55         //从数组中获得指定序号的字符串,作为单元格的标题文字。
 56         cell?.textLabel?.text = comments[(indexPath as NSIndexPath).row]
 57         //设置标题文字的字体大小为12
 58         cell?.textLabel?.font = UIFont.systemFont(ofSize: 12)
 59         //设置文字的颜色为灰色
 60         cell?.textLabel?.textColor = UIColor.gray
 61         //设置标签可显示多行文字
 62         cell?.textLabel?.numberOfLines = 0;
 63         
 64         return cell!
 65     }
 66     
 67     //创建一个类方法,用来根据字符串的长度,计算单元格的高度
 68     class func caculateCellHeight(comment:String)->CGFloat
 69     {
 70         //创建一个字体常量,和单元格的字体大小相同
 71         let font = UIFont.systemFont(ofSize: 12)
 72         //通过计算获得文字的显示区域
 73         let size = comment.boundingRect(with: CGSize(), 
 74                                         options: .usesFontLeading, 
 75                                         attributes: [NSFontAttributeName:font],
 76                                         context: nil);
 77         
 78         //通过显示区域的高度,减去文字至基线的距离,获得文字的高度。
 79         //将显示区域的宽度,除以每行文字的宽度,获得文字的行数,两者相乘获得总的高度。
 80         return (size.height-2*size.origin.y)*(size.width/280.0)
 81     }
 82     
 83     //添加一个代理方法,用来设置单元格的高度
 84     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath)-> CGFloat
 85     {
 86         //根据单元格的序号,获得该单元格将要显示的字符串
 87         let subComments = comments[(indexPath as NSIndexPath).row]
 88         //根据刚刚创建的类方法,计算单元格容纳该字符串所需的高度
 89         let cellHeight =  CustomizeUITableViewCell.caculateCellHeight(comment:subComments)
 90         //然后进行临界判断,从而将高度数值保持在一个合理的范围之内。
 91         if(cellHeight < 30)
 92         {
 93             return 30
 94         }
 95         else
 96         {
 97             return cellHeight
 98         }
 99     }
100     
101     //添加一个方法,用来设置表格的数据源。该方法将在外部的表格中被调用。
102     func setCommentsForTable(_ comments:[String])
103     {
104         //设置自定义单元格的数组属性,作为该单元格的表格的数据源。
105         self.comments = comments
106         
107         //计算单元格内部的表格的高度
108         //首先初始化一个浮点常量
109         var tableHeight:CGFloat = 0
110         //创建一个循环,遍历表格的数据源。
111         //通过对每个单元格的高度进行累计,合计整个表格的高度。
112         for i in 0 ..< comments.count
113         {
114             tableHeight += CustomizeUITableViewCell.caculateCellHeight(comment:comments[i])
115         }
116         
117         //重新绘制表格的显示区域
118         tableView.frame = CGRect(x: 20, y: 0, width: 280, height: tableHeight + 20)
119         //并刷新表格中的数据
120         tableView.reloadData()
121     }
122     
123     //添加一个方法,用来获得单元格内部表格的高度数值
124     func getMyHeight()->CGFloat
125     {
126        //用来获得单元格内部表格的高度数值
127         return tableView.frame.size.height
128     }
129     
130     //最后添加一个必须实现的初始化方法
131     required init(coder aDecoder: NSCoder)
132     {
133         fatalError("init(code:)has not brrn implomented");
134     }
135 }

在项目导航区,打开视图控制器的代码文件【ViewController.swift】

现在开始创建处于外部的表格视图,并在表格中使用刚刚自定义的包含表格的单元格。

  1 import UIKit
  2 
  3 //使当前的视图控制器类,遵循表格的数据源协议UITableViewDataSource和代理协议UITableViewDelegate
  4 class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
  5     
  6     //创建一个数组,作为新闻的标题。
  7     var articles = ["SpaceX wants to launch 4,425 satellites", 
  8     "Free Workshop in Los Angeles, December 10!", 
  9     "Stephen Hawking just gave humanity a due date for finding another planet"]
 10     //创建另一个二维数组,作为新闻的评论内容。
 11     var comments = [["1.Elon Musk's SpaceX wants to launch thousands of satellites into space with the aim of providing super-fast global internet coverage, according to a regulatory filing.","2.SpaceX – the company on a mission to colonize Mars – outlined plans to put 4,425 satellites into space in a Federal Communications Commission (FCC) filing from earlier this week.","3.Billionaire Musk – who is also the chief executive of electric car company Tesla – first announced plans for the project in 2015, with an estimated cost of $10 billion."],["1.Join us for a free Rich Dad Education financial workshop in Los Angeles.","2.All attendees are entered to win a tablet. Save your spot now!","3.Dream of working in Australia?"],["1.If humanity survives the rise of artificial intelligence, the ravages of climate change and the threat of nuclear terrorism in the next century, it doesn't mean we're home free, according to Stephen Hawking.","2.The renowned theoretical physicist has gone as far as providing humanity with a deadline for finding another planet to colonize: We have 1,000 years.","3.Remaining on Earth any longer, Hawking believes, places humanity at great risk of encountering another mass extinction."]]
 12     
 13     override func viewDidLoad() {
 14         super.viewDidLoad()
 15         // Do any additional setup after loading the view, typically from a nib.
 16         
 17         //获得设备的屏幕尺寸
 18         let screenRect = UIScreen.main.bounds
 19         //创建一个矩形区域,作为表格视图的显示区域
 20         let tableRect = CGRect(x: 0,
 21                                y: 20,
 22                                width: screenRect.size.width,
 23                                height: screenRect.size.height - 20)
 24         //初始化一个指定显示区域的表格对象
 25         let tableView = UITableView(frame: tableRect)
 26         
 27         //设置表格对象的数据源为当前的视图控制器对象
 28         tableView.dataSource = self
 29         //设置表格对象的代理为当前的视图控制器对象
 30         tableView.delegate = self
 31         
 32         //设置单元格的分隔线为空白
 33         tableView.separatorStyle = UITableViewCellSeparatorStyle.none
 34         //将表格视图添加到根视图中
 35         self.view.addSubview(tableView)
 36     }
 37     
 38     //添加一个代理方法,用来设置表格的行数
 39     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
 40     {
 41         //在此设置表格的行数为新闻标题数组长度的两倍。
 42         //偶数行用来显示标题,奇数行用来显示评论
 43         return articles.count * 2
 44     }
 45     
 46     //添加一个代理方法,用来初始化或复用表格中的单元格
 47     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)-> UITableViewCell
 48     {
 49         //创建两个字符串常量,作为单元格的复用标识
 50         //1.用于显示新闻标题的偶数行单元格
 51         let cellForArticle = "cellForArticle"
 52         //2.用于显示新闻评论的奇数行的自定义单元格
 53         let cellForComments = "cellForComments"
 54         
 55         //创建两个单元格对象
 56         //1.系统默认样式的单元格
 57         var cell1:UITableViewCell?;
 58         //2.包含子表格的自定义单元格
 59         var cell2:CustomizeUITableViewCell?;
 60         
 61         //判断偶数行
 62         if (indexPath as NSIndexPath).row % 2 == 0
 63         {
 64             //根据偶数行的复用标识,从表格中获得可以复用的单元格
 65             cell1 = tableView.dequeueReusableCell(withIdentifier: cellForArticle)
 66             //如果没有可以复用的单元格
 67             if cell1 == nil
 68             {
 69                 //则初始化一个默认样式的单元格,并设置单元格的复用标识
 70                 cell1 = UITableViewCell(style: UITableViewCellStyle.default,
 71                                         reuseIdentifier: cellForArticle)
 72             }
 73             
 74             //设置单元格的标题文字为新闻的标题
 75             cell1?.textLabel?.text = articles[(indexPath as NSIndexPath).row/2]
 76             //设置标题文字的字体大小为14
 77             cell1?.textLabel?.font = UIFont.systemFont(ofSize: 14)
 78             //设置文字的颜色为白色
 79             cell1?.textLabel?.textColor = UIColor.white
 80             //设置单元格的背景颜色为橙色
 81             cell1?.backgroundColor = UIColor.orange
 82             
 83             //返回设置好的偶数行单元格
 84             return cell1!
 85         }
 86         else
 87         {
 88             //处理奇数行的单元格
 89              //根据奇数行的复用标识,从表格中获得可以复用的单元格
 90             cell2 = tableView.dequeueReusableCell(withIdentifier: cellForComments) as? CustomizeUITableViewCell
 91             //如果没有可以复用的单元格
 92             if cell2 == nil
 93             {
 94                 //则初始化一个默认样式的单元格,并设置单元格的复用标识
 95                 cell2 = CustomizeUITableViewCell(style: UITableViewCellStyle.default,
 96                                                  reuseIdentifier: cellForComments)
 97             }
 98             
 99             //从数组中获得该单元格将要显示的文字内容
100             let subComments = comments[(indexPath as NSIndexPath).row/2]
101             //然后调用自定义单元格对象的,设置子表格的数据源的方法,
102             //在设置子表格数据源的同时,也使子表格的高度做到自适应。
103             cell2?.setCommentsForTable(subComments)
104             
105             //返回奇数行的单元格
106             return cell2!
107         }
108     }
109     
110     //添加一个代理方法,用来设置单元格的高度
111     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
112     {
113         //如果是偶数行的单元格,则设置高度为40
114         if (indexPath as NSIndexPath).row % 2 == 0
115         {
116             return 40
117         }
118         else
119         {
120             //处理奇数行单元格的情况
121             //获得该单元格中的所有文字
122             let subComments = comments[(indexPath as NSIndexPath).row/2]
123             //初始化一个浮点数的变量,用来合计单元格的高度
124             var cellHeight:CGFloat = 0
125             //此处通过相同的方式
126             for i in 0 ..< subComments.count
127             {
128                 //通过累加的方式计算子表格的高度
129                 cellHeight += CustomizeUITableViewCell.caculateCellHeight(comment: subComments[i])
130             }
131 
132             //最后返回该高度与20的和,避免单元格中的文字过于拥挤
133             return cellHeight + 20
134         }
135     }
136     
137     override func didReceiveMemoryWarning() {
138         super.didReceiveMemoryWarning()
139         // Dispose of any resources that can be recreated.
140     }
141 }