I have implemented swipe functionality using UIPanGestureRecognizer
in a project.
What I have done is added PanGesture
to UIView
:
self.panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.panThisCell))
self.view.addGestureRecognizer(panGesture)
And its selector is as:
func panThisCell(recognizer:UIPanGestureRecognizer){
if recognizer != panGesture{ return }
let point = recognizer.locationInView(self.collectionView)
let indexpath = self.collectionView.indexPathForItemAtPoint(point)
if indexpath == nil{ return }
guard let cell = self.collectionView.cellForItemAtIndexPath(indexpath!) as? TileCollectionViewCell else{
return
}
.......
}
And helper methods that animates to show/hide background view are as follows which takes cell of class TileCollectionViewCell
so that I don't have to typecast it later:
func resetConstraintToZero(cell:TileCollectionViewCell, animate:Bool,notifyDelegateDidClose:Bool){
if (cell.startingRightLayoutConstraintConstant == 0 &&
cell.contentViewRightConstraint.constant == 0) {
//Already all the way closed, no bounce necessary
return;
}
cell.contentViewRightConstraint.constant = -kBounceValue;
cell.contentViewLeftConstraint.constant = kBounceValue;
self.updateConstraintsIfNeeded(cell,animated: animate) {
cell.contentViewRightConstraint.constant = 0;
cell.contentViewLeftConstraint.constant = 0;
self.updateConstraintsIfNeeded(cell,animated: animate, completionHandler: {
cell.startingRightLayoutConstraintConstant = cell.contentViewRightConstraint.constant;
})
}
cell.startPoint = CGPoint()
}
func setConstraintsToShowAllButtons(cell:TileCollectionViewCell, animate:Bool,notifyDelegateDidOpen:Bool){
if (cell.startingRightLayoutConstraintConstant == self.getButtonTotalWidth(cell) &&
cell.contentViewRightConstraint.constant == self.getButtonTotalWidth(cell)) {
return;
}
cell.contentViewLeftConstraint.constant = -self.getButtonTotalWidth(cell) - kBounceValue;
cell.contentViewRightConstraint.constant = self.getButtonTotalWidth(cell) + kBounceValue;
self.updateConstraintsIfNeeded(cell,animated: animate) {
cell.contentViewLeftConstraint.constant = -(self.getButtonTotalWidth(cell))
cell.contentViewRightConstraint.constant = self.getButtonTotalWidth(cell)
self.updateConstraintsIfNeeded(cell,animated: animate, completionHandler: {(check) in
cell.startingRightLayoutConstraintConstant = cell.contentViewRightConstraint.constant;
})
}
}
I am thinking of implementing same swipe functionality on to another UICollectionView
which is in the same ViewController
, so I would like to reuse those methods. Custom cells are the exact same.
class TileCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var swipeView: UIView!
@IBOutlet weak var customTextLbl: UILabel!
@IBOutlet weak var customContentView: UIView!
@IBOutlet weak var contentViewLeftConstraint: NSLayoutConstraint!
@IBOutlet weak var contentViewRightConstraint: NSLayoutConstraint!
var startPoint = CGPoint()
var startingRightLayoutConstraintConstant = CGFloat()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
class SecondTileCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var swipeView: UIView!
@IBOutlet weak var customTextLbl: UILabel!
@IBOutlet weak var customContentView: UIView!
@IBOutlet weak var contentViewLeftConstraint: NSLayoutConstraint!
@IBOutlet weak var contentViewRightConstraint: NSLayoutConstraint!
var startPoint = CGPoint()
var startingRightLayoutConstraintConstant = CGFloat()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
I am thinking of making those helper methods accept AnyObject
instead of TileCollectionViewCell
and later downcast to the appropriate type and perform operations. However, this requires an if let
which makes the code more messy.
func resetConstraintToZero(cell:AnyObject, animate:Bool,notifyDelegateDidClose:Bool){
if let firstCell = cell as? TileCollectionViewCell {
if (firstCell.startingRightLayoutConstraintConstant == 0 &&
firstCell.contentViewRightConstraint.constant == 0) {
//Already all the way closed, no bounce necessary
return;
}
firstCell.contentViewRightConstraint.constant = -kBounceValue;
firstCell.contentViewLeftConstraint.constant = kBounceValue;
self.updateConstraintsIfNeeded(firstCell,animated: animate) {
firstCell.contentViewRightConstraint.constant = 0;
firstCell.contentViewLeftConstraint.constant = 0;
self.updateConstraintsIfNeeded(firstCell,animated: animate, completionHandler: {
firstCell.startingRightLayoutConstraintConstant = firstCell.contentViewRightConstraint.constant;
})
}
firstCell.startPoint = CGPoint()
}else {
let secondCel = cell as! SecondTileCollectionViewCell
if (secondCel.startingRightLayoutConstraintConstant == 0 &&
secondCel.contentViewRightConstraint.constant == 0) {
//Already all the way closed, no bounce necessary
return;
}
secondCel.contentViewRightConstraint.constant = -kBounceValue;
secondCel.contentViewLeftConstraint.constant = kBounceValue;
self.updateConstraintsIfNeeded(secondCel,animated: animate) {
secondCel.contentViewRightConstraint.constant = 0;
secondCel.contentViewLeftConstraint.constant = 0;
self.updateConstraintsIfNeeded(secondCel,animated: animate, completionHandler: {
secondCel.startingRightLayoutConstraintConstant = chartCel.contentViewRightConstraint.constant;
})
}
secondCel.startPoint = CGPoint()
}
}
As you can see, the if else
has the same job but only the class is varying. What kind of pattern should I use to deal with this case?
Here is the project