曾經
我們都知道 UITableView
支援實現側滑操作,一般用來實現刪除一個專案,實現起來也很簡單,只需要實現 UITableView
的三個代理方法
- 首先告訴
UITableView
我們需要實現的操作型別,比如返回一個.delete
public func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .delete
}
複製程式碼
- 然後告訴 UITableView 側滑時刪除按鈕上顯示的文字
func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
return "Delete"
}
複製程式碼
- 最後實現按鈕觸發後執行的操作
public func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
// Do somthing
}
複製程式碼
幾個專案下來,我們對這個三部曲早就是滾瓜爛熟了。不過有時候會想,一個簡單的操作按鈕,需要實現三個 Delegate 方法來達到效果,會不會太繁瑣了。。。
更何況還有一件更坑的事情:editingStyleForRow
和titleForDeleteConfirmationButton
這兩個方法屬於UITableViewDelegate
協議,而commit editingStyle
這個方法屬於UITableViewDataSource
協議。
這意味著,如果你為UITableView
實現了通用的DataSource
協議,那麼要實現側滑操作就不可避免要破壞程式碼結構了。。。
另外,側滑支援多項操作的需求越來越旺盛,而此時我們的經典三部曲已經無法勝任工作了。
這時候要麼選擇第三方的實現方案,做好隨時被坑的準備;要麼,自己去實現一個更大的。。。坑?
iOS 8 之後
估計蘋果的工程師也為自己這個天才的設計折服了吧,於是在 iOS 8 引入了一個新的 API:UITableViewRowAction
,先來看一看定義壓壓驚:
@available(iOS 8.0, *)
open class UITableViewRowAction : NSObject, NSCopying {
public convenience init(style: UITableViewRowActionStyle, title: String?, handler: @escaping (UITableViewRowAction, IndexPath) -> Swift.Void)
open var style: UITableViewRowActionStyle { get }
open var title: String?
@NSCopying open var backgroundColor: UIColor? // default background color is dependent on style
@NSCopying open var backgroundEffect: UIVisualEffect?
}
複製程式碼
先來看構造器,便利構造器接受三個屬性:style
、title
、handler
。
title
這個不用說了,肯定就是按鈕顯示的標題了。
style
通過定義可以看到,是一個UITableViewRowActionStyle
型別的列舉值,通過構造器傳入之後便不可更改了,想來是決定操作按鈕的顯示樣式的吧,destructive
這個單詞是不是很熟悉?
@available(iOS 8.0, *)
public enum UITableViewRowActionStyle : Int {
case `default`
case destructive
case normal
}
複製程式碼
繼續往下看到handler
,這是一個閉包,顯然是用來響應按鈕點選事件的了,終於不用另外實現一個Delegate
方法去響應操作事件了麼?自從 iOS 4 之後引入了 block,蘋果已經一發不可收拾了,API 改造大軍正在路上。。。
class 定義裡面還有兩個屬性:
首先看到backgroundColor
,字面意思很好理解,就是背景顏色了,後面註釋了一行小字:default background color is dependent on style。
這證實了我們的猜想:style
屬性決定了按鈕的樣式,也就是背景顏色,當然,我們也可以通過backgroundColor
自己另外指定背景色。
最後一個屬性是backgroundEffect
,是UIVisualEffect
型別的。UIVisualEffect
?!這是啥?有經驗的同學都知道,這是 iOS 7 之後引入的毛玻璃特效啊,不過研究了半天發現並沒有卵用?。也可能是我開啟的方式不對?有知道的同學可以指點下。。。
###實踐
好了,看完了類定義,趕緊來看看怎麼使用吧。先看一下UITableViewDelegate
的定義,關於UITableViewRowAction
只定義了一個方法:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
複製程式碼
終於決定拋棄三部曲了麼?,返回值是個陣列,這是支援多個操作項的節奏啊,廢話少說上程式碼:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let defaultAction = UITableViewRowAction(style: .default, title: "Default") { (action, indexPath) in
self.alertTitle("Default action at \(indexPath)")
}
let normalAction = UITableViewRowAction(style: .normal, title: "Normal") { (action, indexPath) in
self.alertTitle("Normal action at \(indexPath)")
}
let destructiveAction = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
self.alertTitle("Delete action at \(indexPath)")
}
return [defaultAction, normalAction, destructiveAction]
}
func alertTitle(_ title: String) {
let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert, animated: true)
}
複製程式碼
這裡定義了三個UITableViewRowAction
,分別對應不同的style
,執行之後可以發現,default
和destructive
預設都是紅色,normal
預設是灰色。這裡只是簡單定義了一個alertTitle
方法用來響應點選反饋,實際專案中需要替換成特定的業務邏輯。
###結語
至此終於水完了UITableViewRowAction
相關的內容,雖然這是個 iOS 8 就出來的特性了,不過最近才被我注意到,而且還沒有把backgroundEffect
屬性的特性摸清,實在是慚愧。
好訊息是現在大多數 App 都是至少支援 iOS 8 + 了吧?可以再也不用寫繁瑣的三部曲了。