本文将演示如何在表格中嵌套另一个表格并使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 }