简体   繁体   English

如何在 uitableview 中左右滑动单元格,显示左侧图像和右侧图像

[英]how to swipe cells in uitableview left and right, showing an image on left and an image on right

As illustrated, what I need to achieve is when swiping left, a button with an image shows up, the blue one, and when swiping right the green button shows up, how to do this?如图所示,我需要实现的是向左滑动时出现一个带有图像的按钮,蓝色的,向右滑动时出现绿色按钮,如何做到这一点? i use swift and xcode 6.4我使用 swift 和 xcode 6.4

This is what i tried before asking, I was able to show two options with text in the right of a cell, but i don't want that, what is needed is in the illustration, and as said, the buttons need to be images not text.这是我在询问之前尝试过的,我能够在单元格的右侧显示两个带有文本的选项,但我不想要那样,需要的是插图,如上所述,按钮需要是图像不是文字。

在此处输入图片说明

You can subclass UITableViewCell to incorporate a UIPanGestureRecognizer that manipulates the cell's contentView s frame and add your buttons behind the contentView .您可以UIPanGestureRecognizer UITableViewCell以合并一个UIPanGestureRecognizer来操作单元格的contentView框架并将您的按钮添加到contentView后面。

To see how this can work it detail, I added example code on how to do that below for reference.为了详细了解这如何工作,我在下面添加了有关如何执行此操作的示例代码以供参考。 This also adds a tap gesture recognizer to 'close' the action on tap instead of selecting the cell.这还添加了一个点击手势识别器来“关闭”点击操作而不是选择单元格。

Also, as requested in the comments, here is a gif of how this works (showing the colors of the buttons on the side as an indication of action, but you can easily modify the contentView 's frame to be completely overlapping the buttons in your subclass.)此外,根据评论中的要求,这里有一个关于它是如何工作的 gif(显示侧面按钮的颜色作为动作的指示,但您可以轻松修改contentView的框架以完全重叠您的按钮子类。)

在此处输入图片说明

//
//  MWSwipeableTableViewCell.swift
//  MW UI Toolkit
//
//  Created by Jan Greve on 02.12.14.
//  Copyright (c) 2014 Markenwerk GmbH. All rights reserved.
//

import UIKit

protocol MWSwipeableTableViewCellDelegate : NSObjectProtocol {
  func swipeableTableViewCellDidRecognizeSwipe(cell : MWSwipeableTableViewCell)
  func swipeableTableViewCellDidTapLeftButton(cell : MWSwipeableTableViewCell)
  func swipeableTableViewCellDidTapRightButton(cell : MWSwipeableTableViewCell)
}

class MWSwipeableTableViewCell: UITableViewCell {
  weak var delegate : MWSwipeableTableViewCellDelegate?
  var animationOptions : UIViewAnimationOptions = [.AllowUserInteraction, .BeginFromCurrentState]
  var animationDuration : NSTimeInterval = 0.5
  var animationDelay : NSTimeInterval = 0
  var animationSpingDamping : CGFloat = 0.5
  var animationInitialVelocity : CGFloat = 1
  private weak var leftWidthConstraint : NSLayoutConstraint!
  private weak var rightWidthConstraint : NSLayoutConstraint!
  var buttonWidth :CGFloat = 80 {
    didSet(val) {
      if let r = self.rightWidthConstraint {
        r.constant = self.buttonWidth
      }
      if let l = self.leftWidthConstraint {
        l.constant = self.buttonWidth
      }
    }
  }
  private weak var panRecognizer : UIPanGestureRecognizer!
  private weak var buttonCancelTap : UITapGestureRecognizer!

  private var beginPoint : CGPoint = CGPointZero
  weak var rightButton : UIButton! {
    willSet(val) {
      if let r = self.rightButton {
        r.removeFromSuperview()
      }
      if let b = val {
        self.addSubview(b)
        b.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
        b.translatesAutoresizingMaskIntoConstraints = false
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(0)-[v]-(0)-|", options: [], metrics: nil, views: ["v":b]))
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("[v]-(0)-|", options: [], metrics: nil, views: ["v":b]))
        let wc = NSLayoutConstraint(item: b, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.buttonWidth)
        b.addConstraint(wc)
        self.rightWidthConstraint = wc
        self.sendSubviewToBack(b)
      }
    }
  }
  weak var leftButton : UIButton! {
    willSet(val) {
      if let l = self.leftButton {
        l.removeFromSuperview()
      }
      if let b = val {
        self.addSubview(b)
        b.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
        b.translatesAutoresizingMaskIntoConstraints = false
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(0)-[v]-(0)-|", options: [], metrics: nil, views: ["v":b]))
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-(0)-[v]", options: [], metrics: nil, views: ["v":b]))
        let wc = NSLayoutConstraint(item: b, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.buttonWidth)
        b.addConstraint(wc)
        self.leftWidthConstraint = wc
        self.sendSubviewToBack(b)
      }
    }
  }

  override func awakeFromNib() {
    super.awakeFromNib()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
  }

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

  private func commonInit() {

    let pan = UIPanGestureRecognizer(target: self, action: "didPan:")
    pan.delegate = self
    self.addGestureRecognizer(pan)
    self.panRecognizer = pan

    let tap = UITapGestureRecognizer(target: self, action: "didTap:")
    tap.delegate = self
    self.addGestureRecognizer(tap)
    self.buttonCancelTap = tap

    self.contentView.backgroundColor = UIColor.clearColor()
  }


  override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
    if let tap = gestureRecognizer as? UITapGestureRecognizer {
      if tap == self.buttonCancelTap {
                return self.contentView.frame.origin.x != 0
        }
      else {
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
      }
    }
    else if let pan = gestureRecognizer as? UIPanGestureRecognizer {
      let trans = pan.translationInView(self)
      if abs(trans.x) > abs(trans.y) {
        return true
      }
      else if self.contentView.frame.origin.x != 0 {
        return true
      }
      else {
        return false
      }
    }
    else {
      return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }
  }


  func didTap(sender : UITapGestureRecognizer) {
    UIView.animateWithDuration(self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping, initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
      self.contentView.frame.origin.x = 0
      }, completion: nil)
  }

  func didPan(sender: UIPanGestureRecognizer) {
    switch sender.state {
    case .Began:
        self.delegate?.swipeableTableViewCellDidRecognizeSwipe(self)
      self.beginPoint = sender.locationInView(self)
      self.beginPoint.x -= self.contentView.frame.origin.x

    case .Changed:
      let now = sender.locationInView(self)
      let distX = now.x - self.beginPoint.x
      if distX <= 0 {
        let d = max(distX,-(self.contentView.frame.size.width-self.buttonWidth))
        if d > -self.buttonWidth*2 || self.rightButton != nil || self.contentView.frame.origin.x > 0 {
          self.contentView.frame.origin.x = d
        }
        else {
          sender.enabled = false
          sender.enabled = true
        }
      }
      else {
        let d = min(distX,self.contentView.frame.size.width-self.buttonWidth)
        if d < self.buttonWidth*2 || self.leftButton != nil || self.contentView.frame.origin.x < 0 {
          self.contentView.frame.origin.x = d
        }
        else {
          sender.enabled = false
          sender.enabled = true
        }
      }

    default:
        delegate?.swipeableTableViewCellDidRecognizeSwipe(self)
      let offset = self.contentView.frame.origin.x
      if offset > self.buttonWidth && self.leftButton != nil {
        UIView.animateWithDuration(self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping, initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
          self.contentView.frame.origin.x = self.buttonWidth
          }, completion: nil)
      }
      else if -offset > self.buttonWidth && self.rightButton != nil {
        UIView.animateWithDuration(self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping, initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
          self.contentView.frame.origin.x = -self.buttonWidth
          }, completion: nil)
      }
      else {
        UIView.animateWithDuration(self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping, initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
          self.contentView.frame.origin.x = 0
          }, completion: nil)
      }
    }
    }

  func closeButtonsIfShown(animated:Bool = true) -> Bool {
    if self.contentView.frame.origin.x != 0 {
      if animated {
        UIView.animateWithDuration(self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping, initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
          self.contentView.frame.origin.x = 0
          self.panRecognizer.enabled = false
          self.panRecognizer.enabled = true
          }, completion: nil)
      }
      else {
        self.contentView.frame.origin.x = 0
        self.panRecognizer.enabled = false
        self.panRecognizer.enabled = true

      }
      return true
    }
    else {
      return false
    }
  }

  func didTapButton(sender:UIButton!) {
    if let d = delegate {
      if let l = self.leftButton {
        if sender == l {
          d.swipeableTableViewCellDidTapLeftButton(self)
        }
      }
      if let r = self.rightButton {
        if sender == r {
          d.swipeableTableViewCellDidTapRightButton(self)
        }
      }
    }
    self.closeButtonsIfShown(false)
  }

  override func setHighlighted(highlighted: Bool, animated: Bool) {
    let showing = self.contentView.frame.origin.x != 0
    if !showing {
      super.setHighlighted(highlighted, animated: animated)
      self.rightButton?.alpha = showing || !highlighted ? 1 : 0
      self.leftButton?.alpha = showing || !highlighted ? 1 : 0
    }
  }

  override func setSelected(selected: Bool, animated: Bool) {
    let showing = self.contentView.frame.origin.x != 0
    if !showing {
      super.setSelected(selected, animated: animated)
      self.rightButton?.alpha = showing || !selected ? 1 : 0
      self.leftButton?.alpha = showing || !selected ? 1 : 0
    }
  }
}

I could achieved the same result using the swipe gesture recognizer.我可以使用滑动手势识别器获得相同的结果。 Hope this would help.希望这会有所帮助。

  1. Create a table with prototype cell.创建一个带有原型单元格的表格。
  2. Add button both on left side and right side of the cell with image for default control state (you can change the image based on the state control state).在单元格的左侧和右侧添加按钮,并带有图像作为默认控件状态(您可以根据状态控件状态更改图像)。
  3. Add a container view (here it is mainView)on top of the cell covering the entire cell area.在覆盖整个单元格区域的单元格顶部添加一个容器视图(这里是 mainView)。
  4. Create a TableViewCustomCell by subclassing the UITableViewCell通过TableViewCustomCell UITableViewCell创建一个TableViewCustomCell
  5. Change the class of the prototype cell to the custom TableViewCustomCell将原型单元格的类更改为自定义的TableViewCustomCell
  6. Use the following code in TableViewCustomCellTableViewCustomCell使用以下代码

Swift Code : SWIFT代码 :

    import UIKit

    class TableViewCustomCell:UITableViewCell {

    @IBOutlet weak var rightButton: UIButton!
    @IBOutlet weak var leftButton: UIButton!
    @IBOutlet weak var mainView: UIView!
    @IBAction func leftButtonTap(sender: AnyObject) {
        print("leftTap")
    }

    @IBAction func rightButtonTap(sender: AnyObject) {
         print("rightTap")
    }

    override func awakeFromNib() {
        let leftSwipe = UISwipeGestureRecognizer(target: self, action:Selector("swipe:"))
        leftSwipe.direction = .Left;
        self.mainView.addGestureRecognizer(leftSwipe)

        let rightSwipe = UISwipeGestureRecognizer(target: self, action:Selector("swipe:"))
        rightSwipe.direction = .Right;
        self.mainView.addGestureRecognizer(rightSwipe)
    }

    func swipe(sender:AnyObject)
    {
        let swipeGesture:UISwipeGestureRecognizer = sender as! UISwipeGestureRecognizer
        if(swipeGesture.direction == .Left)
        {
            var frame:CGRect = self.mainView.frame;
            frame.origin.x = -self.leftButton.frame.width;
            self.mainView.frame = frame;
        }
        else if(swipeGesture.direction == .Right)
        {
            var frame:CGRect = self.mainView.frame;
            frame.origin.x = +self.rightButton.frame.width;
            self.mainView.frame = frame;
        }

    }
}

There are many ways to go at this, you could look into one of the many existing libraries such as BMXSwipeableCell by Massimiliano Bigatti https://github.com/mbigatti/BMXSwipableCell , where you can either look at the source code or copy it completely.有很多方法可以解决这个问题,您可以查看许多现有库之一,例如 Massimiliano Bigatti https://github.com/mbigatti/BMXSwipableCell 的BMXSwipeableCell ,您可以在其中查看源代码或完全复制它.

Another approach is reading through one of the following two great tutorials:另一种方法是通读以下两个很棒的教程之一:

How to Make a Swipeable TableViewCell With Actions - Without Going Nuts ScrollViews - by Ellen Shapiro: https://www.raywenderlich.com/62435/make-swipeable-table-view-cell-actions-without-going-nuts-scroll-views如何使用动作制作可滑动的 TableViewCell - 无需疯狂的 ScrollViews - Ellen Shapiro: https : //www.raywenderlich.com/62435/make-swipeable-table-view-cell-actions-without-going-nuts-scroll-意见

How to Make a Gesture-Driven To-Do List App Like Clear in Swift - by Audrey Tam: https://www.raywenderlich.com/77974/making-a-gesture-driven-to-do-list-app-like-clear-in-swift-part-1如何在 Swift 中使手势驱动的待办事项列表应用程序清晰- 作者 Audrey Tam: https : //www.raywenderlich.com/77974/making-a-gesture-driven-to-do-list-app-like -clear-in-swift-part-1

To give you a quick idea, the gist is as follows:为了让您快速了解,要点如下:

i.一世。 Create a custom TableViewCell创建自定义TableViewCell

ii. ii. Add a UIPangestureRecognizer添加一个UIPangestureRecognizer

iii.三、 Keep a reference to the original contentView frame, this is necessary since you will be swiping(panning) this contentView left and right.保留对原始contentView框架的引用,这是必要的,因为您将左右滑动(平移)此contentView And keep a reference to the originalCenter of the cell.并保留对单元格原始中心的引用。

iv.四、 Add the images, buttons, or other views you want to reveal to the cell向单元格添加要显示的图像、按钮或其他视图

What happens is that you will guide the appearance of your swipeable cell through the three stages of the UIPanGestureRecognizer : UIGestureStateBegan, UIGestureStateChanged, UIGestureStateEnded什么情况是,你将指导你的滑动式电池的外观经过的三个阶段UIPanGestureRecognizerUIGestureStateBegan, UIGestureStateChanged, UIGestureStateEnded

  1. UIGestureStateBegan : First check if this a horizontal pan, and not a vertical one in the UIGestureDelegate . UIGestureStateBegan :首先检查是否该水平锅,而不是一个垂直的UIGestureDelegate We do this to not confuse the UITableView which, as you might recall scroll Vertically.我们这样做是为了不混淆 UITableView,您可能还记得垂直滚动。 Then get a reference to the original Center of the cell.然后获取对单元格原始中心的引用。

  2. UIGestureStateChanged : As a user moves his finger to the left or to the right, we need to update the appearance of the cell. UIGestureStateChanged :当用户将手指向左或向右移动时,我们需要更新单元格的外观。 By moving the cell's contentView's center using the original center reference, and the movement given to us by the gesture we get exactly the behavior we wish to achieve.通过使用原始中心参考移动单元格的contentView's中心,以及手势给我们的移动,我们得到了我们希望实现的行为。

  3. UIGestureStateEnded : Here we need to decide if we want to keep the revealed image, button etc. in view after the user releases the cell, or if we want to 'snap' back. UIGestureStateEnded :这里我们需要决定是要在用户释放单元格后保持显示的图像、按钮等,还是要“快速”返回。 The threshold for this is really up to to, but will be some sort of percentage change left or right compared to the total width of the cell.这个阈值确实高达,但与单元格的总宽度相比,左侧或右侧会有某种百分比变化。 If you wish to 'snap' back, simply set the contentView 's frame to the original frame we kept a reference to.如果您希望“回退”,只需将contentView的框架设置为我们保留引用的原始框架。 If not, set it to an offset that nicely displays the content you wished to reveal.如果没有,请将其设置为可以很好地显示您希望显示的内容的偏移量。

I hope this helped in getting the concept across, please check out one of those two amazing tutorials for a more detailed explanation!我希望这有助于理解这个概念,请查看这两个惊人的教程之一以获得更详细的解释!

If you want to use library for such function, i would suggest you to use https://github.com/MortimerGoro/MGSwipeTableCell ...如果您想将库用于此类功能,我建议您使用https://github.com/MortimerGoro/MGSwipeTableCell ...

its easy to use and easy customise.它易于使用且易于定制。

The overall idea is simple - your cell's content view is a UIScrollView with views on the sides.总体思路很简单——你的单元格的内容视图是一个UIScrollView ,侧面有视图。

However, the complete working solution is a bit complicated and probably too broad for an answer.但是,完整的工作解决方案有点复杂,而且可能太宽泛而无法给出答案。

I would recommend you to start with an already implemented solution, eg SWTableViewCell (but there are others) and look into the source code.我建议您从已经实现的解决方案开始,例如SWTableViewCell (但还有其他解决方案)并查看源代码。 Or just use it directly.或者直接使用它。 Most of the solutions can be installed using cocoapods and they work both in Swift and Objective-C.大多数解决方案都可以使用cocoapods安装,并且它们可以在 Swift 和 Objective-C 中运行。

based on @Tobi Nary answer, this is 4.2 swift version.基于@Tobi Nary 的回答,这是 4.2 swift 版本。

import UIKit

protocol MWSwipeableTableViewCellDelegate : NSObjectProtocol {
    func swipeableTableViewCellDidRecognizeSwipe(cell : MWSwipeableTableViewCell)
    func swipeableTableViewCellDidTapLeftButton(cell : MWSwipeableTableViewCell)
    func swipeableTableViewCellDidTapRightButton(cell : MWSwipeableTableViewCell)
}

class MWSwipeableTableViewCell: UITableViewCell {
    weak var delegate : MWSwipeableTableViewCellDelegate?
    var animationOptions : UIView.AnimationOptions = [.allowUserInteraction, .beginFromCurrentState]
    var animationDuration : TimeInterval = 0.5
    var animationDelay : TimeInterval = 0
    var animationSpingDamping : CGFloat = 0.5
    var animationInitialVelocity : CGFloat = 1
    private weak var leftWidthConstraint : NSLayoutConstraint!
    private weak var rightWidthConstraint : NSLayoutConstraint!
    var buttonWidth :CGFloat = 80 {
        didSet(val) {
            if let r = self.rightWidthConstraint {
                r.constant = self.buttonWidth
            }
            if let l = self.leftWidthConstraint {
                l.constant = self.buttonWidth
            }
        }
    }
    private weak var panRecognizer : UIPanGestureRecognizer!
    private weak var buttonCancelTap : UITapGestureRecognizer!

    private var beginPoint : CGPoint = CGPoint.zero
    weak var rightButton : UIButton! {
        willSet(val) {
            if let r = self.rightButton {
                r.removeFromSuperview()
            }
            if let b = val {
                self.addSubview(b)
                b.addTarget(self, action: Selector(("didTapButton:")), for: .touchUpInside)
                b.translatesAutoresizingMaskIntoConstraints = false
                self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(0)-[v]-(0)-|", options: [], metrics: nil, views: ["v":b]))
                self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "[v]-(0)-|", options: [], metrics: nil, views: ["v":b]))
                let wc = NSLayoutConstraint(item: b, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil,     attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: self.buttonWidth)
                b.addConstraint(wc)
                self.rightWidthConstraint = wc
                self.sendSubviewToBack(b)
            }
        }
    }
    weak var leftButton : UIButton! {
        willSet(val) {
            if let l = self.leftButton {
                l.removeFromSuperview()
            }
            if let b = val {
                self.addSubview(b)
                b.addTarget(self, action: Selector("didTapButton:"), for: .touchUpInside)
                b.translatesAutoresizingMaskIntoConstraints = false
                self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(0)-[v]-(0)-|", options: [], metrics: nil, views: ["v":b]))
                self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|-(0)-[v]", options: [], metrics: nil, views: ["v":b]))
                let wc = NSLayoutConstraint(item: b, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil,     attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: self.buttonWidth)
                b.addConstraint(wc)
                self.leftWidthConstraint = wc
                self.sendSubviewToBack(b)
            }
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }

    private func commonInit() {

        let pan = UIPanGestureRecognizer(target: self, action: Selector(("didPan:")))
        pan.delegate = self
        self.addGestureRecognizer(pan)
        self.panRecognizer = pan

        let tap = UITapGestureRecognizer(target: self, action: Selector(("didTap:")))
        tap.delegate = self
        self.addGestureRecognizer(tap)
        self.buttonCancelTap = tap

        self.contentView.backgroundColor = UIColor.clear
    }


    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if let tap = gestureRecognizer as? UITapGestureRecognizer {
            if tap == self.buttonCancelTap {
                return self.contentView.frame.origin.x != 0
            }
            else {
                return super.gestureRecognizerShouldBegin(gestureRecognizer)
            }
        }
        else if let pan = gestureRecognizer as? UIPanGestureRecognizer {
            let trans = pan.translation(in: self)
            if abs(trans.x) > abs(trans.y) {
                return true
            }
            else if self.contentView.frame.origin.x != 0 {
                return true
            }
            else {
                return false
            }
        }
        else {
            return super.gestureRecognizerShouldBegin(gestureRecognizer)
        }
    }


    func didTap(sender : UITapGestureRecognizer) {
        UIView.animate(withDuration: self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping, initialSpringVelocity:     self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
            self.contentView.frame.origin.x = 0
        }, completion: nil)
    }

    func didPan(sender: UIPanGestureRecognizer) {
        switch sender.state {
        case .began:
            self.delegate?.swipeableTableViewCellDidRecognizeSwipe(cell: self)
            self.beginPoint = sender.location(in: self)
            self.beginPoint.x -= self.contentView.frame.origin.x

        case .changed:
            let now = sender.location(in: self)
            let distX = now.x - self.beginPoint.x
            if distX <= 0 {
                let d = max(distX,-(self.contentView.frame.size.width-self.buttonWidth))
                if d > -self.buttonWidth*2 || self.rightButton != nil || self.contentView.frame.origin.x > 0 {
                    self.contentView.frame.origin.x = d
                }
                else {
                    sender.isEnabled = false
                    sender.isEnabled = true
                }
            }
            else {
                let d = min(distX,self.contentView.frame.size.width-self.buttonWidth)
                if d < self.buttonWidth*2 || self.leftButton != nil || self.contentView.frame.origin.x < 0 {
                    self.contentView.frame.origin.x = d
                }
                else {
                    sender.isEnabled = false
                    sender.isEnabled = true
                }
            }

        default:
            delegate?.swipeableTableViewCellDidRecognizeSwipe(cell: self)
            let offset = self.contentView.frame.origin.x
            if offset > self.buttonWidth && self.leftButton != nil {
                UIView.animate(withDuration: self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping,     initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
                    self.contentView.frame.origin.x = self.buttonWidth
                }, completion: nil)
            }
            else if -offset > self.buttonWidth && self.rightButton != nil {
                UIView.animate(withDuration: self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping,     initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
                    self.contentView.frame.origin.x = -self.buttonWidth
                }, completion: nil)
            }
            else {
                UIView.animate(withDuration: self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping,     initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
                    self.contentView.frame.origin.x = 0
                }, completion: nil)
            }
        }
    }

    func closeButtonsIfShown(animated:Bool = true) -> Bool {
        if self.contentView.frame.origin.x != 0 {
            if animated {
                UIView.animate(withDuration: self.animationDuration, delay: self.animationDelay, usingSpringWithDamping: self.animationSpingDamping,     initialSpringVelocity: self.animationInitialVelocity, options: self.animationOptions, animations: { () -> Void in
                    self.contentView.frame.origin.x = 0
                    self.panRecognizer.isEnabled = false
                    self.panRecognizer.isEnabled = true
                }, completion: nil)
            }
            else {
                self.contentView.frame.origin.x = 0
                self.panRecognizer.isEnabled = false
                self.panRecognizer.isEnabled = true

            }
            return true
        }
        else {
            return false
        }
    }

    func didTapButton(sender:UIButton!) {
        if let d = delegate {
            if let l = self.leftButton {
                if sender == l {
                    d.swipeableTableViewCellDidTapLeftButton(cell: self)
                }
            }
            if let r = self.rightButton {
                if sender == r {
                    d.swipeableTableViewCellDidTapRightButton(cell: self)
                }
            }
        }
        self.closeButtonsIfShown(animated: false)
    }

    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
        let showing = self.contentView.frame.origin.x != 0
        if !showing {
            super.setHighlighted(highlighted, animated: animated)
            self.rightButton?.alpha = showing || !highlighted ? 1 : 0
            self.leftButton?.alpha = showing || !highlighted ? 1 : 0
        }
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        let showing = self.contentView.frame.origin.x != 0
        if !showing {
            super.setSelected(selected, animated: animated)
            self.rightButton?.alpha = showing || !selected ? 1 : 0
            self.leftButton?.alpha = showing || !selected ? 1 : 0
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM