有时要实现一个复杂的页面布局,单单使用
UITableView 实现不了,需要通过
UITableView 和
UICollectionView 结合实现,即每个单元格
tableViewCell 中都嵌套一个
collectionView。下面通过样例演示如何实现。
1,效果图
(1)表格中每一个单元格对应一个月份的图书列表。
(2)单元格中头部显示月份标题。内部通过
collectionView 显示当月所有书籍封面图片,数量不定。整个单元格高度自适应。
2,如何实现单元格高度自适应
(1)我们要对
collectionView 设置个高度约束。当在单元格中更新
collectionView 的数据时,要获取这个
collectionView 的真实的内容高度(
contentSize.height),然后用
contentSize.height 来更新
collectionView 的高度约束。这样就实现了单元格内部
collectionView 的高度自适应。
(2)而对于单元格
tableViewCell 的高度自适应,是通过
AutoLayout 特性实现的。利用内容将
cell 撑起来。
1
2
3
4
|
//设置estimatedRowHeight属性默认值
self
.tableView!.estimatedRowHeight = 44.0
//rowHeight属性设置为UITableViewAutomaticDimension
self
.tableView!.rowHeight =
UITableViewAutomaticDimension
|
3,实现步骤
(1)新建一个自定义的
collectionView 单元格类:
MyCollectionViewCell,同时勾选“
Also create XIB file”
(2)在
MyCollectionViewCell.xib 中添加一个
ImageView,并设置好约束。同时在对应的类中作关联
(3)
MyCollectionViewCell.swift 代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
import
UIKit
class
MyCollectionViewCell
:
UICollectionViewCell
{
//用于显示封面缩略图
@IBOutlet
weak
var
imageView:
UIImageView
!
override
func
awakeFromNib() {
super
.awakeFromNib()
}
}
|
(4)新建一个自定义的 tableView 单元格类: MyTableViewCell ,同时勾选“ Also create XIB file ”
(5)在
MyTableViewCell.xib 中添加一个
Label 和一个
CollectionView,并设置好约束。同时在对应的类中作关联。
其中
Label 设置的是上、下、左、右4个约束:
CollectionView 设置的是左、右、下以及高度这个4个约束:
同时调整下
CollectionView 的
Cell Size 和
Min Spacing:
(6)
MyTableViewCell.swift 代码如下:
(7)在
StoryBoard 主视图中添加一个
TableView,并设置好约束。同时在对应的类中作关联。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
import
UIKit
class
MyTableViewCell
:
UITableViewCell
,
UICollectionViewDelegate
,
UICollectionViewDataSource
{
//单元格标题
@IBOutlet
weak
var
titleLabel:
UILabel
!
//封面图片集合列表
@IBOutlet
weak
var
collectionView:
UICollectionView
!
//collectionView的高度约束
@IBOutlet
weak
var
collectionViewHeight:
NSLayoutConstraint
!
//封面数据
var
images:[
String
] = []
override
func
awakeFromNib() {
super
.awakeFromNib()
//设置collectionView的代理
self
.collectionView.delegate =
self
self
.collectionView.dataSource =
self
// 注册CollectionViewCell
self
.collectionView!.register(
UINib
(nibName:
"MyCollectionViewCell"
, bundle:
nil
),
forCellWithReuseIdentifier:
"myCell"
)
}
//加载数据
func
reloadData(title:
String
, images:[
String
]) {
//设置标题
self
.titleLabel.text = title
//保存图片数据
self
.images = images
//collectionView重新加载数据
self
.collectionView.reloadData()
//更新collectionView的高度约束
let
contentSize =
self
.collectionView.collectionViewLayout.collectionViewContentSize
collectionViewHeight.constant = contentSize.height
self
.collectionView.collectionViewLayout.invalidateLayout()
}
//返回collectionView的单元格数量
func
collectionView(_ collectionView:
UICollectionView
,
numberOfItemsInSection section:
Int
) ->
Int
{
return
images.count
}
//返回对应的单元格
func
collectionView(_ collectionView:
UICollectionView
,
cellForItemAt indexPath:
IndexPath
) ->
UICollectionViewCell
{
let
cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"myCell"
,
for
: indexPath)
as
!
MyCollectionViewCell
cell.imageView.image =
UIImage
(named: images[indexPath.item])
return
cell
}
//绘制单元格底部横线
override
func
draw(_ rect:
CGRect
) {
//线宽
let
lineWidth = 1 /
UIScreen
.main.scale
//线偏移量
let
lineAdjustOffset = 1 /
UIScreen
.main.scale / 2
//线条颜色
let
lineColor =
UIColor
(red: 0xe0/255, green: 0xe0/255, blue: 0xe0/255, alpha: 1)
//获取绘图上下文
guard
let
context =
UIGraphicsGetCurrentContext
()
else
{
return
}
//创建一个矩形,它的所有边都内缩固定的偏移量
let
drawingRect =
self
.bounds.insetBy(dx: lineAdjustOffset, dy: lineAdjustOffset)
//创建并设置路径
let
path =
CGMutablePath
()
path.move(to:
CGPoint
(x: drawingRect.minX, y: drawingRect.maxY))
path.addLine(to:
CGPoint
(x: drawingRect.maxX, y: drawingRect.maxY))
//添加路径到图形上下文
context.addPath(path)
//设置笔触颜色
context.setStrokeColor(lineColor.cgColor)
//设置笔触宽度
context.setLineWidth(lineWidth)
//绘制路径
context.strokePath()
}
override
func
setSelected(_ selected:
Bool
, animated:
Bool
) {
super
.setSelected(selected, animated: animated)
}
}
|
(8)
ViewController.swift 代码如下:
源码下载:
hangge_1591.zip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
import
UIKit
//每月书籍
struct
BookPreview
{
var
title:
String
var
images:[
String
]
}
class
ViewController
:
UIViewController
,
UITableViewDelegate
,
UITableViewDataSource
{
//所有书籍数据
let
books = [
BookPreview
(title:
"五月新书"
, images: [
"0.jpg"
,
"1.jpg"
,
"2.jpg"
,
"3.jpg"
,
"4.jpg"
,
"5.jpg"
,
"6.jpg"
]),
BookPreview
(title:
"六月新书"
, images: [
"7.jpg"
,
"8.jpg"
,
"9.jpg"
]),
BookPreview
(title:
"七月新书"
, images: [
"10.jpg"
,
"11.jpg"
,
"12.jpg"
,
"13.jpg"
])
]
//显示内容的tableView
@IBOutlet
weak
var
tableView:
UITableView
!
override
func
loadView() {
super
.loadView()
}
override
func
viewDidLoad() {
super
.viewDidLoad()
//设置tableView代理
self
.tableView!.delegate =
self
self
.tableView!.dataSource =
self
//去除单元格分隔线
self
.tableView!.separatorStyle = .none
//创建一个重用的单元格
self
.tableView!.register(
UINib
(nibName:
"MyTableViewCell"
, bundle:
nil
),
forCellReuseIdentifier:
"myCell"
)
//设置estimatedRowHeight属性默认值
self
.tableView!.estimatedRowHeight = 44.0
//rowHeight属性设置为UITableViewAutomaticDimension
self
.tableView!.rowHeight =
UITableViewAutomaticDimension
}
//在本例中,只有一个分区
func
numberOfSectionsInTableView(tableView:
UITableView
) ->
Int
{
return
1;
}
//返回表格行数
func
tableView(_ tableView:
UITableView
, numberOfRowsInSection section:
Int
) ->
Int
{
return
self
.books.count
}
//创建各单元显示内容(创建参数indexPath指定的单元)
func
tableView(_ tableView:
UITableView
, cellForRowAt indexPath:
IndexPath
)
->
UITableViewCell
{
let
cell = tableView.dequeueReusableCell(withIdentifier:
"myCell"
)
as
!
MyTableViewCell
//下面这两个语句一定要添加,否则第一屏显示的collection view尺寸,以及里面的单元格位置会不正确
cell.frame = tableView.bounds
cell.layoutIfNeeded()
//重新加载单元格数据
cell.reloadData(title:books[indexPath.row].title,
images: books[indexPath.row].images)
return
cell
}
override
func
didReceiveMemoryWarning() {
super
.didReceiveMemoryWarning()
}
}
|
功能修改:每个单元格只显示一行封面图片
上面的样例中,每个单元格内的图片是全部显示出来,有多少显示多少,高度自适应。
我们还可以换种展示方法,每个单元格,即每个
collectionView 只显示一行数据,图片如果多的话可以通过左右滑动查看。
1,效果图
2,实现原理
我们只需要把
collectionView 的滚动方向改成水平方向即可。
如果不需要显示横向的滚动条,可以去掉“
Shows Horizontal Indicator”的勾选。
原文链接: http://www.hangge.com/blog/cache/detail_1591.html