成品图

Dec-01-2020 16-04-59

首先可以看出是使用UICollectionView为基础构建的,我们先声明一个View继承自UICollectionView,并且遵循UICollectionViewDelegateUICollectionViewDataSource

1
2
3
class SelectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource {

}

然后声明一些基础的需要用到的常变量

1
2
3
4
5
6
private let cellId = "SELECTION_VIEW_CELL_ID" // Cell 注册ID
private var selectedIdx: Int = -1 // -1 则为不选择
private var data: [String] // 数据
private var callBack: ((Int)->Void)? // 回调函数
// 是否能够取消选择
var allowsCancelSelection: Bool = false

然后填写一下初始化函数和回调,可以讲的一点主要是didSelect函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if callBack != nil {
callBack!(indexPath.row)
}

if selectedIdx == -1 {
selectedIdx = indexPath.row
(collectionView.cellForItem(at: indexPath) as! FBTagCollectionViewCell).toggle()
} else if selectedIdx == indexPath.row {
if allowsCancelSelection {
selectedIdx = -1
(collectionView.cellForItem(at: indexPath) as! FBTagCollectionViewCell).toggle()
}
return
} else {
(collectionView.cellForItem(at: IndexPath(row: selectedIdx, section: indexPath.section)) as! FBTagCollectionViewCell).toggle()
(collectionView.cellForItem(at: indexPath) as! FBTagCollectionViewCell).toggle()
selectedIdx = indexPath.row
}
}

可以看到对于一些条件进行了判断,以及让回调函数能够获取到选择的下标,cell的toggle()函数用于改变背景颜色(即选中状态)

再添加一些供外部调用的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 外部调用方法
extension SelectionView {
func getIdx() -> Int {
return selectedIdx
}

func addCallBack(_ callBack: @escaping ((Int)->Void)) {
self.callBack = callBack
}

func updateData(data: [String]) {
self.data = data
reloadData()
}
}

大功告成,以下是完整代码。

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
import UIKit

class SelectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource {
private let cellId = "SELECTION_VIEW_CELL_ID" // Cell 注册ID
private var selectedIdx: Int = -1 // -1 则为不选择
private var data: [String] // 数据
private var callBack: ((Int)->Void)? // 回调函数
// 是否能够取消选择
var allowsCancelSelection: Bool = false

init(data: [String], collectionViewLayout: UICollectionViewFlowLayout, callBack: ((Int)->Void)? = nil) {
self.data = data
self.callBack = callBack

super.init(frame: .zero, collectionViewLayout: collectionViewLayout)
register(FBTagCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
backgroundColor = .white
delegate = self
dataSource = self
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FBTagCollectionViewCell
cell.update(by: data[indexPath.row], selected: indexPath.row == selectedIdx)
return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if callBack != nil {
callBack!(selectedIdx == indexPath.row ? -1 : indexPath.row)
}

if selectedIdx == -1 {
selectedIdx = indexPath.row
(collectionView.cellForItem(at: indexPath) as! FBTagCollectionViewCell).toggle()
} else if selectedIdx == indexPath.row {
if allowsCancelSelection {
selectedIdx = -1
(collectionView.cellForItem(at: indexPath) as! FBTagCollectionViewCell).toggle()
}
return
} else {
if let cell = collectionView.cellForItem(at: IndexPath(item: selectedIdx, section: indexPath.section)) {
(cell as! FBTagCollectionViewCell).toggle()
}
(collectionView.cellForItem(at: indexPath) as! FBTagCollectionViewCell).toggle()
selectedIdx = indexPath.row
}
}
}

// 外部调用方法
extension SelectionView {
func getIdx() -> Int {
return selectedIdx
}

func addCallBack(_ callBack: @escaping ((Int)->Void)) {
self.callBack = callBack
}

func updateData(data: [String]) {
self.data = data
reloadData()
}
}