iOS 开发中,有一种常用的模式,标记配置,mark & configure
步骤是:
-
标记,
mark
-
状态恢复,
reset
-
配置,
configure
本文通过三个例子,来说明
前两个例子,是选中状态
例子一,按钮点击
三个按钮,选中一个,其余两个取消选中
常规做法
操作指定,reset 剩余
代码的维护成本大
class ViewController: UIViewController {
@IBOutlet weak var lhs: StateBtn!
@IBOutlet weak var mid: StateBtn!
@IBOutlet weak var rhs: StateBtn!
func setup(){
lhs.addTarget(self, action: #selector(btnOne), for: .touchUpInside)
mid.addTarget(self, action: #selector(btnTwo), for: .touchUpInside)
rhs.addTarget(self, action: #selector(btnThree), for: .touchUpInside)
}
@objc
func btnOne(){
lhs.beSelected = true
mid.beSelected = false
rhs.beSelected = false
}
@objc
func btnTwo(){
lhs.beSelected = false
mid.beSelected = true
rhs.beSelected = false
}
@objc
func btnThree(){
lhs.beSelected = false
mid.beSelected = false
rhs.beSelected = true
}
}
模式后
统一重置后,再操作
代码维护成本,有减轻
@objc
func btnOne(){
resetAll()
lhs.beSelected = true
}
@objc
func btnTwo(){
resetAll()
mid.beSelected = true
}
@objc
func btnThree(){
resetAll()
rhs.beSelected = true
}
func resetAll(){
lhs.beSelected = false
mid.beSelected = false
rhs.beSelected = false
}
例子二, table View
更加明显一些
三个 cell ,选中一个,其余两个 cell 取消选中
常规做法:
操作在 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
,
选中后,捞出前一个 cell, 捞出现在选中的 cell,
对两个 cell 修改状态
可能的问题是,捞出前一个 cell, 崩掉
因为可能前一个 cell 不在屏幕上,进入了复用池,没有啦
现在选中的 cell, 肯定在屏幕上,肯定存在
class ViewController{
@IBOutlet weak var table: UITableView!
func setup(){
table.register(UINib(nibName: TableCell.k, bundle: nil), forCellReuseIdentifier: TableCell.k)
table.delegate = self
table.dataSource = self
table.rowHeight = 60
table.reloadData()
}
}
extension ViewController: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 操作上一个
if let last = lastSelectedItem{
guard last != indexPath.row else{
return
}
if let cell = tableView.cellForRow(at: IndexPath(row: last, section: 0)) as? TableCell{
cell.beSelected = false
}
}
// 操作当前
if let cell = tableView.cellForRow(at: indexPath) as? TableCell{
cell.beSelected = true
}
lastSelectedItem = indexPath.row
}
}
extension ViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = tableView.dequeueReusableCell(withIdentifier: TableCell.k, for: indexPath)
return item
}
}
模式后
之前记录的是上一次选择的 row, 这里记录的是当前选中的 row
逻辑更加简单
分两个阶段处理,
-
选中代理中,记录,并刷新列表
-
刷新列表,会调用配置方法,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
里面根据数据,选择状态
没有上一步的隐患
效果增强,就用 deep diff
class ViewController: UIViewController {
@IBOutlet weak var table: UITableView!
var selectedItem: Int? = nil
}
extension ViewController: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedItem = indexPath.row
tableView.reloadData()
}
}
extension ViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = tableView.dequeueReusableCell(withIdentifier: TableCell.k, for: indexPath)
if let cel = item as? TableCell{
if let row = selectedItem, row == indexPath.row{
cel.beSelected = true
}
else{
cel.beSelected = false
}
}
return item
}
}
例子三,MBProgressHUD
bar 进度条
- (void)barDeterminateExample {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
// 标记
hud.mode = MBProgressHUDModeDeterminateHorizontalBar;
}
标记后,触发
- (void)setMode:(MBProgressHUDMode)mode {
if (mode != _mode) {
_mode = mode;
[self updateIndicators];
}
}
走更新
- (void)updateIndicators {
if (mode == MBProgressHUDModeDeterminateHorizontalBar) {
// reset 原来的
[indicator removeFromSuperview];
// 使用新的
indicator = [[MBBarProgressView alloc] init];
[self.bezelView addSubview:indicator];
}
// 二次标记
[self setNeedsUpdateConstraints];
}
重新做布局
#pragma mark - Layout
- (void)updateConstraints {
// ...
}