文中代碼基于swift4.0 demo github: XXCellAndDeleteAction
一、 自定義卡片式的tableViewCell
1. 要想cell之間有間隔,可以用一種“假間隔”的方式設置
將cell設大一點,再添加一個卡片的view,和cell的contenView間隔一定的距離
2. 注意顏色設置,避免以下問題
- 1 是cell的顏色;
- 2 是tableView當左劃時多出的一個UISwipeActionPullView的背景顏色(ios11之前是不存在這個問題的);
- 3 是刪除View的背景顏色
刪除View高度(與cell高度一致)與卡片的高度不一樣,所以1、2、3的顏色要保持一致,否則呈現的效果很丑。
cellDele.png
3. ios11對刪除按鈕的層級做了改變。最顯著的改變是從是UITableViewCell的子視圖變成了UITableView的子視圖(引用自:http://www.lxweimin.com/p/779f36c21632)。
iOS 8-10: UITableView -> UITableViewCell -> UITableViewCellDeleteConfirmationView -> _UITableViewCellActionButton
iOS 11 (Xcode 8編譯): UITableView -> UITableViewWrapperView -> UISwipeActionPullView -> UISwipeActionStandardButton
iOS 11 (Xcode 9編譯): UITableView -> UISwipeActionPullView -> UISwipeActionStandardButton
4. 為了適配ios11,需要改變UISwipeActionPullView的背景顏色。
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 11.0, *) {
for view in tableView.subviews {
if view.isKind(of: NSClassFromString("UISwipeActionPullView")!) {
//這里可以改變view的背景顏色
}
}
}
}
二、 自定義左劃刪除按鈕
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let kCellActionWidth: CGFloat = 100
let whitespace = whitespaceString(width: kCellActionWidth)//根據寬度返回占位的空格字符串
let deleAction = UITableViewRowAction(style: .default, title: whitespace) { (action, indexPath) in
//delete callback
}
deleAction.backgroundColor = UIColor(patternImage: getDeleteIcon())
return [deleAction]
}
1. 刪除按鈕的寬度,是根據給定刪除按鈕的文字來變化的。
2. 只顯示圖片不顯示文字。根據預定的刪除按鈕的寬度,全部用" "空格來占位。
//根據寬度返回帶有空格的string類型
fileprivate func whitespaceString(font: UIFont = UIFont.systemFont(ofSize: 15), width: CGFloat) -> String {
let kPadding: CGFloat = 20
let mutable = NSMutableString(string: "")
let attribute = [NSAttributedStringKey.font: font]
while mutable.size(withAttributes: attribute).width < width - (2 * kPadding) {
mutable.append(" ")
}
return mutable as String
}
3. 給刪除按鈕設置圖片,注意刪除按鈕沒有image屬性(ios11新出了一個API帶有image屬性,但是也無法實現我想要的效果,后面會提到)
deleAction.backgroundColor = UIColor(patternImage: getDeleteIcon())
func getDeleteIcon() -> UIImage {
let kCellActionWidth: CGFloat = 100
let kCellHeight: CGFloat = 176
let kActionImageSize: CGFloat = 18
let kImageBackViewSize: CGFloat = 44
let view = UIView(frame: CGRect(x: 0, y: 0, width: kCellActionWidth, height: kCellHeight))
let deleteBackView = UIView(frame: CGRect(x: (kCellActionWidth - kImageBackViewSize) / 2,
y: (kCellHeight - kImageBackViewSize) / 2,
width: kImageBackViewSize,
height: kImageBackViewSize))
deleteBackView.layer.cornerRadius = kImageBackViewSize / 2
deleteBackView.clipsToBounds = true
deleteBackView.backgroundColor = UIColor.white
let imageView = UIImageView(frame: CGRect(x: (kCellActionWidth - kActionImageSize) / 2,
y: (kCellHeight - kActionImageSize) / 2,
width: kActionImageSize,
height: kActionImageSize))
imageView.image = UIImage(named: "delete")
view.backgroundColor = UIColor(red: 224.0/255.0, green: 227.0/255.0, blue: 232.0/255.0, alpha: 1.0)
view.addSubview(deleteBackView)
view.addSubview(imageView)
return view.image()
}
4. 將view轉化成image
view.image() //給view添加一個extension實現將view轉化成image的功能
extension UIView {
func image() -> UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
guard let context = UIGraphicsGetCurrentContext() else {
return UIImage()
}
layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
ios10.3.png
ios11.png
5. 設置完以上幾步,ios11之前顯示就很正常了。但是ios11有一點瑕疵。因為ios11 用空格來占位不起作用了。如果action的title 是正常的字符,則會根據字符多少設置刪除按鈕的寬度。如果action的title為nil或者“ ”空格,那么action會給一個默認的寬度,這個寬度比我之前設置的100要小,為了讓顯示更美觀,修改方法getDeleteIcon() 中垃圾桶背景view與垃圾桶的x值。
var deletBackViewX: CGFloat = 0
var imageViewX: CGFloat = 0
if #available(iOS 11.0, *) {
deletBackViewX = kActionImageSize / 2
imageViewX = kActionImageSize / 2 + (kImageBackViewSize - kActionImageSize) / 2
} else {
deletBackViewX = (kCellActionWidth - kImageBackViewSize) / 2
imageViewX = (kCellActionWidth - kActionImageSize) / 2
}
修改垃圾桶和垃圾桶背景的x值后.png
ageView2/2/w/1240)
6. ios11出了下面的新API,UIContextualAction可以直接設置image。但是image以及文字的顏色默認都是白色。image會被渲染成白色,而我的垃圾桶是紅色,所以無用。當然也可以修改成紅的,通過修改tableView里面imageView的appearance。但是這個設置對所有tableView中的imageView都有效。所以有時候不是很適用。
@available(iOS 11.0, *)
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .normal, title: nil) { (action, view, completeHandler) in
//delete action
}
return UISwipeActionsConfiguration(actions: [deleteAction])
}
image.png