Skip to content

Instantly share code, notes, and snippets.

@adriencog
Last active March 18, 2020 13:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save adriencog/9baf1489d507ff282ecbdc29d61e2b78 to your computer and use it in GitHub Desktop.
Save adriencog/9baf1489d507ff282ecbdc29d61e2b78 to your computer and use it in GitHub Desktop.
import UIKit
class SwipeCell: UITableViewCell {
var scrollView: UIScrollView!
var containerView: UIView!
var actionView: UIView!
let minOffset: CGFloat = 30
var isLeftSideVisible:Bool {
return scrollView.contentOffset.x < 0
}
var isRightSideVisible:Bool {
return scrollView.contentOffset.x > 0
}
var actionLabel: UILabel!
var selectedAction: SwipeAction?
var leftActions: [SwipeAction] = []
var rightActions: [SwipeAction] = []
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {}
override func setSelected(_ selected: Bool, animated: Bool) {}
override func layoutSubviews() {
super.layoutSubviews()
scrollView.contentInset = UIEdgeInsets(top: 0, left: bounds.width, bottom: 0, right: bounds.width)
scrollView.contentSize = contentView.bounds.size
}
func setup() {
scrollView = UIScrollView(frame: bounds)
scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
scrollView.contentSize = bounds.size
scrollView.contentInset = UIEdgeInsets(top: 0, left: bounds.width, bottom: 0, right: bounds.width)
scrollView.delegate = self
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
scrollView.decelerationRate = UIScrollViewDecelerationRateFast
contentView.addSubview(scrollView)
actionView = UIView(frame: CGRect(origin: .zero, size: bounds.size))
actionView.backgroundColor = UIColor.gray
actionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
scrollView.addSubview(actionView)
containerView = UIView(frame: scrollView.bounds)
containerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
containerView.backgroundColor = UIColor.white
scrollView.addSubview(containerView)
actionLabel = UILabel(frame: CGRect(x: 10, y: 0, width: bounds.width - 20, height: bounds.height))
actionLabel.font = UIFont.systemFont(ofSize: 12)
actionLabel.autoresizingMask = [.flexibleWidth, .flexibleHeight]
actionLabel.textColor = .white
actionLabel.baselineAdjustment = .alignCenters
actionLabel.adjustsFontSizeToFitWidth = true
actionView.addSubview(actionLabel)
}
func findVisibleAction() -> SwipeAction? {
let offsetX = abs(scrollView.contentOffset.x)
let actionsWidth = scrollView.contentSize.width - minOffset
if offsetX < minOffset {
return nil
}
if isLeftSideVisible {
let actionOffset = actionsWidth / CGFloat(leftActions.count)
let i = max(0, Int((offsetX - minOffset) / actionOffset))
return i < leftActions.count ? leftActions[i] : nil
}
if isRightSideVisible {
let actionOffset = actionsWidth / CGFloat(rightActions.count)
let i = max(0, Int((offsetX - minOffset) / actionOffset))
return i < rightActions.count ? rightActions[i] : nil
}
return nil
}
func performAction() {
dismissAction()
}
func dismissAction() {
selectedAction = nil
scrollView.setContentOffset(.zero, animated: false)
}
}
extension SwipeCell : UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetX = scrollView.contentOffset.x
actionView.frame = CGRect(origin: CGPoint(x: offsetX, y: 0), size: actionView.frame.size)
let action = selectedAction ?? findVisibleAction()
actionView.backgroundColor = action?.color ?? UIColor.lightGray
actionLabel.textAlignment = isRightSideVisible ? .right : .left
actionLabel.text = action?.title
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let offsetX = abs(scrollView.contentOffset.x)
let width = scrollView.contentSize.width
if offsetX < minOffset {
targetContentOffset.pointee = .zero
}else{
if isLeftSideVisible { targetContentOffset.pointee.x = -width }
else if isRightSideVisible { targetContentOffset.pointee.x = width }
}
selectedAction = findVisibleAction()
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if selectedAction != nil {
performAction()
} else {
dismissAction()
}
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
selectedAction = nil
}
}
import UIKit
struct CustomAction: SwipeAction {
var title: String
var color: UIColor
}
class ViewController: UITableViewController {
let cellIdentifier = "SwipeCell"
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(SwipeCell.self, forCellReuseIdentifier: cellIdentifier)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! SwipeCell
cell.rightActions = [
CustomAction(title: "Action R1", color: UIColor.red),
CustomAction(title: "Action R2", color: UIColor.blue),
CustomAction(title: "Action R3", color: UIColor.purple)
]
cell.leftActions = [
CustomAction(title: "Action L1", color: UIColor.green),
CustomAction(title: "Action L2", color: UIColor.orange)
]
return cell
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment