web-dev-qa-db-fra.com

comment faire glisser les cellules dans uitableview gauche et droite, montrant une image à gauche et une image à droite

Comme illustré, ce que je dois réaliser, c’est que lorsque vous balayez vers la gauche, un bouton avec une image apparaît, le bleu, et lorsque vous balayez vers la droite, le bouton vert apparaît, comment faire cela? J'utilise Swift et xcode 6.4

C’est ce que j’ai essayé avant de demander, j’ai pu montrer deux options avec du texte à droite d’une cellule, mais je ne veux pas de cela, c’est ce qui est nécessaire dans l’illustration. pas du texte.

 enter image description here

15
DeyaEldeen

Vous pouvez sous-classe UITableViewCell pour incorporer une UIPanGestureRecognizer qui manipule le cadre contentViews de la cellule et ajouter vos boutons derrière la contentView.

Pour voir comment cela peut fonctionner détail, j'ai ajouté un exemple de code sur la façon de le faire ci-dessous pour référence. Cela ajoute également un outil de reconnaissance des gestes du tap pour fermer l'action sur le tap au lieu de sélectionner la cellule.

Aussi, comme demandé dans les commentaires, voici un gif de la façon dont cela fonctionne (montrant les couleurs des boutons sur le côté pour indiquer l’action, mais vous pouvez facilement modifier le cadre de la contentView afin qu’il chevauche complètement les boutons de votre sous-classe. )

 enter image description here

//
//  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
    }
  }
}
18
Tobi Nary

Il existe de nombreuses façons de procéder. Vous pouvez consulter l'une des nombreuses bibliothèques existantes, telles que BMXSwipeableCell de Massimiliano Bigatti https://github.com/mbigatti/BMXSwipableCell , où vous pouvez consulter le code source. ou le copier complètement.

Une autre approche consiste à lire l'un des deux excellents tutoriels suivants:

Comment créer une TableViewCell glissable avec des actions - Sans écrous ScrollViews - par Ellen Shapiro: https://www.raywenderlich.com/62435/make-swipeable-table-view-cell-actions -without-going-nuts-scroll-views

Comment créer une liste de tâches dirigée par le geste comme au clair dans Swift - par Audrey Tam: https://www.raywenderlich.com/77974/making-a-gesture-driven-to-do -list-app-like-clear-in-Swift-part-1

Pour vous donner une idée rapide, le Gist est le suivant:

je. Créer une TableViewCell personnalisée

ii. Ajouter une UIPangestureRecognizer

iii. Conservez une référence au cadre contentView original. Cela est nécessaire car vous allez balayer (déplacer) cette contentView à gauche et à droite. Et gardez une référence au centre d'origine de la cellule. 

iv. Ajoutez les images, les boutons ou les autres vues que vous souhaitez révéler à la cellule. 

Ce qui se passe, c’est que vous allez guider l’apparence de votre cellule balayable tout au long des trois étapes de la UIPanGestureRecognizer: UIGestureStateBegan, UIGestureStateChanged, UIGestureStateEnded

  1. UIGestureStateBegan: Commencez par vérifier s'il s'agit d'un panoramique horizontal et non vertical dans la UIGestureDelegate. Nous faisons cela pour ne pas confondre UITableView qui, comme vous vous en souvenez peut-être, fait défiler verticalement. Ensuite, obtenez une référence au centre d'origine de la cellule.

  2. UIGestureStateChanged: lorsqu'un utilisateur déplace son doigt vers la gauche ou vers la droite, nous devons mettre à jour l'apparence de la cellule. En déplaçant le centre contentView's de la cellule en utilisant la référence de centre d'origine et le mouvement que le geste nous a donné, nous obtenons exactement le comportement que nous souhaitons obtenir.

  3. UIGestureStateEnded: Ici, nous devons décider si nous voulons garder l'image révélée, le bouton, etc. après que l'utilisateur a relâché la cellule, ou si nous voulons «revenir» en arrière. Le seuil pour cela est vraiment jusqu'à, mais ce sera une sorte de pourcentage de changement à gauche ou à droite par rapport à la largeur totale de la cellule. Si vous souhaitez "revenir" en arrière, définissez simplement le cadre de la contentView sur le cadre d'origine auquel nous avons conservé une référence. Sinon, réglez-le sur un décalage qui affiche bien le contenu que vous souhaitez révéler.

J'espère que cela vous a aidé à faire passer le concept. Veuillez consulter l'un de ces deux tutoriels étonnants pour une explication plus détaillée!

4
trdavidson

Je pouvais obtenir le même résultat en utilisant le programme de reconnaissance de geste par balayage. J'espère que cela aiderait.

  1. Créez un tableau avec une cellule prototype.
  2. Le bouton Ajouter se trouve à gauche et à droite de la cellule avec une image pour l'état de contrôle par défaut (vous pouvez modifier l'image en fonction de l'état de contrôle d'état).
  3. Ajoutez une vue conteneur (ici c'est mainView) au-dessus de la cellule couvrant toute la zone de la cellule.
  4. Créez une TableViewCustomCell en sous-classant la UITableViewCell
  5. Remplacez la classe de la cellule prototype par la variable personnalisée TableViewCustomCell
  6. Utilisez le code suivant dans TableViewCustomCell

Code rapide :

    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;
        }

    }
}
4
Ronald

Si vous souhaitez utiliser la bibliothèque pour une telle fonction, je vous suggère d'utiliser https://github.com/MortimerGoro/MGSwipeTableCell ...

son facile à utiliser et facile à personnaliser.

1
Dev_Tandel

L'idée générale est simple: la vue du contenu de votre cellule est une UIScrollView avec des vues sur les côtés.

Cependant, la solution de travail complète est un peu compliquée et probablement trop large pour une réponse.

Je vous recommanderais de commencer avec une solution déjà mise en œuvre, par exemple. SWTableViewCell (mais il y en a d'autres) et examinez le code source. Ou simplement l'utiliser directement. La plupart des solutions peuvent être installées avec cocoapods et fonctionnent à la fois en Swift et en Objective-C.

0
Sulthan