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.
Vous pouvez sous-classe UITableViewCell
pour incorporer une UIPanGestureRecognizer
qui manipule le cadre contentView
s 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. )
//
// 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
}
}
}
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
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.
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.
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!
Je pouvais obtenir le même résultat en utilisant le programme de reconnaissance de geste par balayage. J'espère que cela aiderait.
TableViewCustomCell
en sous-classant la UITableViewCell
TableViewCustomCell
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;
}
}
}
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.
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.