前言

Eureka是一个纯Swift库,它能帮你快速优雅地创建一个TableView。这个库本身也提供了大量内置的不同功能的Cell,使用上也很简单。如果内置的Cell样式或功能不能满足需要,你也可以自定义Cell

使用Eureka设置TableView的代码大概是下面这样:

1
2
3
4
5
6
7
8
9
form +++ Section()
<<< LabelRow() {
$0.title = "LabelRow"
$0.value = "Default Value"
}.cellSetup({ (cell, row) in
cell.accessoryType = .disclosureIndicator
}).onCellSelection({ (cell, row) in
print("cell selection")
})

本文主要介绍Eureka的基本使用和自定义Cell的步骤。你可以在这里查看本文的Demo。

基本使用

Eureka的基本使用主要是三步

  • 1. 新建ViewController并将ViewController设置为FormViewController的子类
  • 2. 添加Section
  • 3. 添加Row

新建ViewController

显示tableView首先得有一个控制器,这里我们新建一个控制器并将它设置成FormViewController的子类,如下所示:

1
2
3
4
5
class ViewController: FormViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}

FormViewController本身是UIViewController的子类,而且Eureka框架已经在其中添加和设置好了tableView,所以我们开发时不用操心布局,仅仅关注交互逻辑就可以了。

添加Section

FormViewControllertableViewstyle属性值为.grouped,这里我们添加多少个Section就会自动生成多少个组,添加语法如下:

1
form +++ Section()

有的人看到这里或许有点奇怪,+++是个什么语法,好像没见过啊。其实这是Eureka使用了Swift自定义运算符的特性,定义+++这个中缀运算符,它在源文件里是这么定义的:

1
infix operator +++ : FormPrecedence

上面这个添加Section的语法定义是这样的:

1
2
3
4
5
@discardableResult
public func +++ (left: Form, right: Section) -> Form {
left.append(right)
return left
}

这里Form遵从了RangeReplaceableCollection这个协议,重写了append这个方法,具体实现有兴趣的可以去看源码。

添加Row

Row的创建和设置是所有步骤的核心,所有的交互逻辑都是在这里完成的。Eureka内置了数十种常用的Row,这里我们添加最常用的三种Row

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
form +++ Section()
<<< LabelRow() {
$0.title = "LabelRow"
$0.value = "Default Value"
}.cellSetup({ (cell, row) in
cell.accessoryType = .disclosureIndicator
}).onCellSelection({ (cell, row) in
print("cell selection")
})
<<< TextRow(tag: "TextRow")
.cellSetup({ (cell, row) in
row.tag = "TextRow"
row.title = "TextRow"
row.placeholder = "Input your message"
})
.cellUpdate({ (cell, row) in
print("cell update")
})
<<< SwitchRow() {
$0.tag = "SwitchValue"
$0.title = "SwitchRow"
$0.value = true
}.onChange({ (row) in
print("value changed: \(row.value ?? false)")
})

<<<同样是Eureka自定义的中缀运算符,作用是将Row添加到对应的Section中。在上面的代码中,我是在Row的生成方法的闭包中为titlevalue赋值,这个操作同样也可以放在cellSetup方法中(这个操作只会在Row创建时调用),效果是一样的。需要动态刷新的值需要在cellUpdate方法中设置。Eureka同时也提供了onCellSelectiononChange这样的响应方法,在里面定义其实响应逻辑即可。

至此,Eureka的基本使用就全部完成了。如果Eureka框架自带的Row已经能完全满足你的需求,就不需要往下看了。但如果你不满足于内置Row,那么我们继续看看如何自定义CellRow

自定义Cell

这里我们来定义一个模拟软件更新的Cell,效果图如下:

效果图

定义结构体

首先,我们需要一个结构体Software方便为Cell赋值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum UpdateState: Int {
case toUpdate = 0
case updating
case alreadyNewest
}

struct Software: Equatable {
var name: String
var updateState: UpdateState
}

func == (lhs: Software, rhs: Software) -> Bool {
return lhs.name == rhs.name
}

这里有一点需要注意的是,定义的类或者结构体必须遵从Equatable协议,否则在自定义Cell里使用时会报错。

定义Cell

定义好了结构体,接下来就是实现Cell部分。

自定义EurekaCell和自定义普通UITableViewCell一样,首先要选择使用纯代码创建还是xib创建。这里我们使用xib的方式。新建自定义Cell,如下图:

添加Cell

自定义布局,Cell连线,UpdateCell的代码如下:

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
final class UpdateCell: Cell<Software>, CellType {

@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var updateButton: UIButton!
@IBOutlet weak var aniContainerView: UIView!
@IBOutlet weak var noNeedUpdateLabel: UILabel!

private var shapeLayer = CAShapeLayer()

override func setup() {

selectionStyle = .none
height = { return 44 }

//这里省略布局代码

}

override func update() {
guard let software = row.value else {
return
}
titleLabel.text = software.name
updateUI(software.updateState)
}

}

在创建UpdateCell类的时候,有几点需要注意:

  • 指明为Cell赋值时使用的类
  • 遵从CellType协议
  • 指定Cell的高度

在上面的代码的,Setup方法只会在Cell创建时调用一次,可以在这里写布局代码,而Update方法会在每次刷新的时候调用,可以在这里给CellsubViews赋值。

定义Row

接下来还需要自定义Row,从属于上面我们刚刚定义的Cell,并在里面加载xib

1
2
3
4
5
6
7
8
final class UpdateRow: Row<UpdateCell>, RowType {

required init(tag: String?) {
super.init(tag: tag)
cellProvider = CellProvider<UpdateCell>(nibName: "UpdateCell")
}

}

添加自定义CellSection

自定义Cell创建完成后,就可以像使用框架中自带的Row一样来使用我们的自定义Row

1
2
3
<<< UpdateRow() {
$0.value = Software(name: "My Software", updateState: .toUpdate)
}

总结

其实Eureka的使用比较简单,熟练操作后会是快速构建UITableView的利器。本文的Demo可以在这里查看。