方案一:
通过自定义
UITableView
在layoutSubviews
方法中添加对应控件(适用于单个按钮)
- 使用弊端:
1.按钮宽度需要自己预估
2.控件宽度需要func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String?
代理方法中来填充 - 核心代码
class HWTableView: UITableView {
private var unifiedColor = UIColor.red
private lazy var deleteBtn: UIButton = {
let deleteBtn = UIButton(type: .custom)
deleteBtn.backgroundColor = unifiedColor
deleteBtn.setTitle("删除", for: .normal)
deleteBtn.setTitleColor(UIColor.white, for: .normal)
deleteBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15)
deleteBtn.setImage(UIImage(named: "垃圾桶白"), for: .normal)
return deleteBtn
}()
override func layoutSubviews() {
super.layoutSubviews()
if #available(iOS 11.0, *) {
for subview in self.subviews {
if subview.isKind(of: NSClassFromString("UISwipeActionPullView")!) {
subview.backgroundColor = unifiedColor
for view in subview.subviews {
if view.isKind(of: NSClassFromString("UISwipeActionStandardButton")!) {
view.backgroundColor = unifiedColor
let frame = CGRect(x: 0, y: 0, width: 80, height: view.bounds.size.height)
deleteBtn.frame = frame
deleteBtn.hw_locationAdjust(buttonMode: .top, spacing: 5)
view.addSubview(deleteBtn)
view.bringSubviewToFront(deleteBtn)
break }
}
break }
}
} else { // IOS 10以及以下
for subview in subviews {
if subview.isKind(of: NSClassFromString("UITableViewCellDeleteConfirmationView")!) {
subview.backgroundColor = unifiedColor
for view in subview.subviews {
if view.isKind(of: UIButton.self) {
view.backgroundColor = unifiedColor
let frame = CGRect(x: 0, y: 0, width: 80, height: view.bounds.size.height)
deleteBtn.frame = frame
deleteBtn.hw_locationAdjust(buttonMode: .top, spacing: 5)
view.addSubview(deleteBtn)
view.bringSubviewToFront(deleteBtn)
break}
}
break}
}
}
}
}
方案二:
通过自定义Cell来添加控件
- 优势:不仅适用于
UITableView
也适用于UICollectionView
- 弊端:毕竟是自定义的很多地方需要注意,必须处理 不然会出现各种各样的Bug
- 核心代码
let width = UIScreen.main.bounds.size.width
class LeftSlideTableViewCell: UITableViewCell {
private var btnwidth: CGFloat = 80
public var closeOtherCellSwipeBlock:(()->())?
private var isOpenLeft = false
private lazy var btn_1: UIButton = {
let btn = UIButton()
btn.setTitle("按钮1", for: UIControl.State.normal)
btn.frame = CGRect(x: width+btnwidth, y: 0, width: btnwidth, height: self.bounds.size.height)
btn.backgroundColor = UIColor.red
btn.setImage(UIImage(named: "垃圾桶白"), for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 12)
btn.tag = 100
btn.addTarget(self, action: #selector(btnClick(btn:)), for: UIControl.Event.touchUpInside)
btn.hw_locationAdjust(buttonMode: .top, spacing: 5)
return btn
}()
private lazy var btn_2: UIButton = {
let btn = UIButton()
btn.setTitle("按钮2", for: UIControl.State.normal)
btn.frame = CGRect(x: width, y: 0, width: btnwidth, height: self.bounds.size.height)
btn.backgroundColor = UIColor.blue
btn.tag = 101
btn.setImage(UIImage(named: "垃圾桶白"), for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 12)
btn.addTarget(self, action: #selector(btnClick(btn:)), for: UIControl.Event.touchUpInside)
btn.hw_locationAdjust(buttonMode: .top, spacing: 5)
return btn
}()
@objc func btnClick(btn: UIButton) {
self.closeLeftSwipe()
// 可以添加点击按钮回调
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func layoutSubviews() {
super.layoutSubviews()
/// 问题点 修改contentView宽度 解决超出父控件按钮点击无响应问题 这里如果是XIB的话估计要修改一下约束了(未尝试)
if self.contentView.frame.size.width != width + btnwidth*2 {
let oldFrame = self.contentView.frame
self.contentView.frame = CGRect(x: oldFrame.origin.x, y: oldFrame.origin.y, width: width + btnwidth*2, height: oldFrame.size.height)
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUI()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func setUI() {
self.contentView.addSubview(btn_1)
self.contentView.addSubview(btn_2)
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(swipe(sender:)))
leftSwipe.direction = UISwipeGestureRecognizer.Direction.left
self.contentView.addGestureRecognizer(leftSwipe)
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(swipe(sender:)))
rightSwipe.direction = UISwipeGestureRecognizer.Direction.right
self.contentView.addGestureRecognizer(rightSwipe)
}
@objc private func swipe(sender: UISwipeGestureRecognizer) {
if sender.direction == UISwipeGestureRecognizer.Direction.left { // 左滑
if isOpenLeft {return}
closeOtherCellSwipeBlock?()
UIView.animate(withDuration: 0.5) {
let oldFrame = self.contentView.frame
let frame = CGRect(x: oldFrame.origin.x-self.btnwidth*2, y: oldFrame.origin.y, width: oldFrame.size.width, height: oldFrame.size.height)
self.contentView.frame = frame
// self.contentView.center = CGPoint(x: (width)*0.5-160, y: self.bounds.height*0.5) // 有Bug
}
isOpenLeft = true
} else if sender.direction == UISwipeGestureRecognizer.Direction.right { // 右滑
closeLeftSwipe()
}
}
/// 关闭左滑,恢复原状
public func closeLeftSwipe() {
if isOpenLeft == false {return}
UIView.animate(withDuration: 0.5) {
// self.contentView.center = CGPoint(x: width*0.5, y: self.bounds.height*0.5)
let oldFrame = self.contentView.frame
let frame = CGRect(x: 0, y: oldFrame.origin.y, width: oldFrame.size.width, height: oldFrame.size.height)
self.contentView.frame = frame
}
isOpenLeft = false
}
}
问题点一:
因为添加的控件是超出屏幕外
的,如果不修改contentView的宽度
,那么添加到contentView
中的控件点击事件无法触发
,如果修改后通过xib
控件添加约束
那么就需要处理右边约束
了
override func layoutSubviews() {
super.layoutSubviews()
/// 问题点 修改contentView宽度 解决超出父控件按钮点击无响应问题 这里如果是XIB的话估计要修改一下约束了(未尝试)
if self.contentView.frame.size.width != width + btnwidth*2 {
let oldFrame = self.contentView.frame
self.contentView.frame = CGRect(x: oldFrame.origin.x, y: oldFrame.origin.y, width: width + btnwidth*2, height: oldFrame.size.height)
}
}
问题点二:
因为view
的真实Frame
只有在layoutSubviews
中才能拿到,以下代码修改center
或者frame
必须是真实的
不然会出现bug
UIView.animate(withDuration: 0.5) {
let oldFrame = self.contentView.frame
let frame = CGRect(x: oldFrame.origin.x-self.btnwidth*2, y: oldFrame.origin.y, width: oldFrame.size.width, height: oldFrame.size.height)
self.contentView.frame = frame
// self.contentView.center = CGPoint(x: (width)*0.5-160, y: self.bounds.height*0.5) // 有Bug
}
问题点三:
因为Cell
中是在固定方法
中处理
的子控件
,所有创建是必须
走固定的方法
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "id") as? LeftSlideTableViewCell
if cell == nil {
cell = LeftSlideTableViewCell.init(style: UITableViewCell.CellStyle.default, reuseIdentifier: "id")
}
/// 左滑回调 用于关闭其他左滑
cell?.closeOtherCellSwipeBlock = { [weak self] in
self?.closeOtherCellSwipeBlock()
}
cell?.textLabel?.text = itemArray[indexPath.row]
return cell ?? UITableViewCell()
}
问题点四:
什么时候关闭左滑,这是需要考虑在其中的
/// 1.一个cell触发左滑 需要关闭其他左滑
cell?.closeOtherCellSwipeBlock = { [weak self] in
self?.closeOtherCellSwipeBlock()
}
///2. 在滑动tableView时必须关闭所有左滑 不然会出现Cell复用Bug
func scrollViewDidScroll(_ scrollView: UIScrollView) {
closeOtherCellSwipeBlock()
}
///3.点击cell 必须关闭左滑 不然会出现Bug
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
let cell = tableView.cellForRow(at: indexPath) as! LeftSlideTableViewCell
cell.closeLeftSwipe()
}
/// 4.点击按钮时必须关闭左滑 不然会出现Bug
@objc func btnClick(btn: UIButton) {
self.closeLeftSwipe()
}
小结:目前暂时只找出以上问题因为我现在用到的,使用方案一就可以解决了,故没有更深一步研究