美文网首页iOS程序犭袁swift@IT·互联网
仿照QQ聊天单元格左滑效果

仿照QQ聊天单元格左滑效果

作者: 蓝色达风 | 来源:发表于2017-05-09 15:56 被阅读156次

前言

作为一个iOS开发者,在实际工作我们无数次跟UITableView打交道,UITableView拥有着诸多优点,强大,好用,性能好等。单元格作为UITableView重要的部分,通常会被自定义以适应不同的需求。今天简单模仿下仿照QQ聊天单元格左滑效果。


单元格左滑效果演示.gif
1、利用系统API实现单元格左滑效果
@available(iOS 8.0, *)
    optional public func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? // supercedes -tableView:titleForDeleteConfirmationButtonForRowAtIndexPath: if return value is non-nil

该函数由iOS 8.0以后提供,是UITableViewDelegate中的一个函数,用起来简单方便,如果产品需求简单倒是直接建议用此方法实现对应功能。

 func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
        //  实例化一个操作对象UITableViewRowAction
        let deleteAction = UITableViewRowAction(style: .default, title: "  删除        ") { (_, indexpath) in
            // 点击触发事件
        }
        
        let test2 = UITableViewRowAction(style: .default, title: "测试") {  (_, indexpath) in
            // 点击触发事件
        }
        // 设置操作按钮的背景色
        test2.backgroundColor = UIColor.blue
        
        // 返回操作对象数组
        return [deleteAction, test2]
    }

以下是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?
}

通过以上接口可以看出,操作按钮的设置有很大局限性,背景颜色可以设置,但是宽度无法设置,又或操作按钮想显示图片,则无法设置。

2、自定义实现单元格左滑效果(仿照QQ聊天单元格左滑效果)

这里贴一下主要代码块,说下思路,比较简单,有兴趣的朋友可以下载Demo看一下,在文章问候有链接
自定义单元格,继承自UITableViewCell


自定义单元格.png

提供实例化对象类方法

    /**
     实例化对象类方法
     rightButtonBgColors: 右边操作按钮背景色数组,不传则显示默认颜色(右边操作按钮最多三个,多传无用)
     rightButtonTitles: 右边操作按钮标题数组(右边操作按钮最多三个,多传无用)
     closureClickRightButton: 点击右边操作按钮触发事件,参数是button,可以根据button的title或者tag判断点击了哪个操作按钮
     */
    class func swipeTableViewCell(tableView: UITableView, rightButtonBgColors:[UIColor]? = nil, rightButtonTitles: [String], closureClickRightButton: ((_ button: UIButton) -> ())?) -> (JYSwipeTableViewCell) {
        var cell = tableView.dequeueReusableCell(withIdentifier: "JYSwipeTableViewCellId") as? JYSwipeTableViewCell
        if cell == nil {
            cell = Bundle.main.loadNibNamed("JYSwipeTableViewCell", owner: nil, options: nil)?.first as? JYSwipeTableViewCell
        }
        cell?.tableView = tableView
        if let rightButtonBgColors = rightButtonBgColors, rightButtonBgColors.count > 0 {
            cell?.rightButtonBgColors = rightButtonBgColors
        }
        cell?.rightButtonTitles = rightButtonTitles
        cell?.closureClickRightButton = closureClickRightButton
        return cell!
    }

手势添加:两个手势,滑动和点击

 override func awakeFromNib() {
        super.awakeFromNib()
        
        selectionStyle = .none
        isSwiped = false
        
        // overlayerContentView添加滑动手势
        let pan = UIPanGestureRecognizer(target: self, action: #selector(overlayerContentViewDidSwip(pan:)))
        overlayerContentView.addGestureRecognizer(pan)
        
        // overlayerContentView添加点击手势
        let tap = UITapGestureRecognizer(target: self, action: #selector(overlayerContentViewDidTap(tap:)))
        overlayerContentView.addGestureRecognizer(tap)
    }

手势触发事件,主要处理就在这里,根据滑动状态(开始滑动、滑动中、滑动结束)的变化处理自定义的内容视图的x坐标。有一个注意点:当前滑动动画正在进行时禁调tableView的isUserInteractionEnabled(手势交互),以免当前动画正在进行,用户紧接着滑动另一个单元格,然后同时两个单元格显示操作按钮。

// MARK - 手势触发事件
extension JYSwipeTableViewCell {
    /// 点击overlayerContentView后出发的方法
    @objc fileprivate func overlayerContentViewDidTap(tap: UITapGestureRecognizer) {
        // 恢复已滑动单元格
        recoverSwipedCell()
    }
    
    // 滑动overlayerContentView后出发的方法
    @objc fileprivate func overlayerContentViewDidSwip(pan: UIPanGestureRecognizer) {
        var translationX = pan.translation(in: self).x
        // print("translationX: \(translationX)")
        
        if pan.state == .began {// 滑动开始
            // 恢复已滑动单元格
            recoverSwipedCell()
            
        }else if pan.state == .changed {// 滑动中
            if translationX < 0 {// 从右往左滑
                if isSwiped == false {// 当前不是滑动后的状态
                    translationX = translationX < maxSwipValue ? maxSwipValue : translationX
                    overlayerContentViewLeftLC.constant = translationX
                }
                
            }else {// 从左往右滑
                if isSwiped == true {// 处在滑动后的状态
                    UIView.animate(withDuration: animateDuration, animations: {[weak self] in
                        self?.overlayerContentView.frame = (self?.bounds)!
                        
                        }, completion: {[weak self] (_) in
                            self?.isSwiped = false
                    })
                }
            }
            
        }else if pan.state == .ended, isSwiped == false {// 滑动结束,且单元格当前不是滑动后的状态
            if translationX > maxSwipValue * 0.3 {// 滑过距离没有超过maxSwipValue的三分之一
                overlayerContentViewLeftLC.constant = 0
                
            }else {// 滑过距离超过maxSwipValue的三分之一
                overlayerContentViewLeftLC.constant = maxSwipValue
            }
            
            tableView?.isUserInteractionEnabled = false
            UIView.animate(withDuration: animateDuration, animations: {[weak self] in
                self?.contentView.layoutIfNeeded()
                
                }, completion: {[weak self] (_) in
                    if self?.overlayerContentViewLeftLC.constant == maxSwipValue {
                        self?.isSwiped = true
                    }
                    self?.tableView?.isUserInteractionEnabled = true
            })
        }
    }
    
    /// 恢复已滑动单元格
    fileprivate func recoverSwipedCell() {
        guard let tableView = tableView else {
            return
        }
        for cell in tableView.visibleCells {
            guard let cell = cell as? JYSwipeTableViewCell else {
                continue
            }
            if cell.isSwiped == true {// 已经处在滑动后的状态
                cell.overlayerContentViewLeftLC.constant = 0
                UIView.animate(withDuration: animateDuration, animations: {
                    cell.contentView.layoutIfNeeded()
                    
                }, completion: { (_) in
                    cell.isSwiped = false
                })
            }
        }
    }
}

Demo链接

相关文章

网友评论

    本文标题:仿照QQ聊天单元格左滑效果

    本文链接:https://www.haomeiwen.com/subject/ywzbtxtx.html