iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
1
Software Development

iOS 三十天上架記帳 APP系列 第 16

Money Mom - 客製化 UITableViewCell 滑動之背景按鈕

每個快速記帳的 UITableViewCell 中的結構如下:

滑動時,只要改變 Main View 的位置即可。

在每一個 Cell 後面加入按鈕

我們可以透過在 Cell 後面加入按鈕,然後用前面的 View 蓋住它們,來達到滑動後,背後出現按鈕的效果:

https://github.com/SwipeCellKit/SwipeCellKit

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    topInnerView.addSubview(amountLabel)
    topInnerView.addSubview(playButton)

    mainView.addSubview(topInnerView)
    mainView.addSubview(tagCollectionView)

    hiddenView.addSubview(editButton)
    hiddenView.addSubview(deleteButton)

    contentView.addSubview(hiddenView)
    contentView.addSubview(mainView)
}

加入手勢:UIPanGestureRecognizer

private lazy var panGestureRecognizer: UIPanGestureRecognizer = {
    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGesture))
    panGestureRecognizer.delegate = self
    return panGestureRecognizer
}()

extension QuickRecordTableViewCell {
    @objc private func panGesture(sender: UIPanGestureRecognizer) {
        if sender.state == .began || sender.state == .changed {
            let translation = sender.translation(in: contentView)

            mainViewLeftAnchor?.constant += translation.x

            if (mainViewLeftAnchor?.constant ?? 0) < 0 {
                hiddenView.backgroundColor = MMColor.red
            } else {
                hiddenView.backgroundColor = MMColor.green
            }

            sender.setTranslation(.zero, in: contentView)
        }

        if sender.state == .ended, let mainViewLeftAnchor = mainViewLeftAnchor {
            contentView.layoutIfNeeded()

            if mainViewLeftAnchor.constant < 0, abs(mainViewLeftAnchor.constant) >= deleteButton.frame.width {
                mainViewLeftAnchor.constant = -deleteButton.frame.width - contentView.layoutMargins.right
            } else if mainViewLeftAnchor.constant > 0, abs(mainViewLeftAnchor.constant) >= editButton.frame.width {
                mainViewLeftAnchor.constant = editButton.frame.width + contentView.layoutMargins.left
            } else {
                mainViewLeftAnchor.constant = 0
            }

            UIView.animate(withDuration: 0.2) { () in
                self.contentView.layoutIfNeeded()
            }
        }
    }
}

原理是我們偵測手勢拖動時,將按鈕前面那層 mainView 跟著左右橫移,一旦 mainView 移動之後,就會有後方按鈕逐漸顯現的錯覺。

最後我們在偵測使用者橫移超過按鈕的寬度後,只要使用者結束橫移,我們就把 mainView 往回移,移到剛好符合按鈕大小的寬度,使用者就可以點擊該按鈕。

加入判斷避免與 UITableView 本身的手勢衝突

因為 UIPanGestureRecognizer 是可以垂直、水平拖動,因此會跟 UITableView 本身的垂直拖動衝突,所以我們要加入一些條件,避免兩個手勢同時做動:

  1. 水平速度大於垂直速度時,允許我們的手勢偵測
  2. 垂直速度大於水平速度時,禁止我們的手勢偵測

如下所示:

extension QuickRecordTableViewCell {
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == panGestureRecognizer, let velocity = (gestureRecognizer as? UIPanGestureRecognizer)?.velocity(in: contentView) {
            return abs(velocity.x) > abs(velocity.y)
        }

        return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }
}

展示

  1. 往左滑顯示刪除按鈕,點擊後刪除
  2. 往右滑顯示編輯按鈕,點擊後進入(下一篇才會加入跳轉功能)

程式碼:GitHub

下一篇就會開始實做「整理」快速記帳的功能囉!


上一篇
Money Mom - 第二波攻勢號角響起
下一篇
Money Mom - 實做新增收支記錄的界面 Part 1
系列文
iOS 三十天上架記帳 APP30

尚未有邦友留言

立即登入留言