Skip to content

Instantly share code, notes, and snippets.

@ArtiomKha
Created April 5, 2023 19:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ArtiomKha/fd6a33da7d82448a4a3ca9fc2299b372 to your computer and use it in GitHub Desktop.
Save ArtiomKha/fd6a33da7d82448a4a3ca9fc2299b372 to your computer and use it in GitHub Desktop.
import UIKit
struct Colors {
static let background = #colorLiteral(red: 0.657153666, green: 0.8692060113, blue: 0.6173200011, alpha: 1)
static let draggedBackground = #colorLiteral(red: 0.462745098, green: 0.7843137255, blue: 0.5764705882, alpha: 1)
static let tint = #colorLiteral(red: 0.1019607843, green: 0.4588235294, blue: 0.6235294118, alpha: 1)
}
protocol SlideToActionButtonDelegate: AnyObject {
func didFinish()
}
class SlideToActionButton: UIView {
let handleView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = Colors.draggedBackground
view.layer.cornerRadius = 12
view.layer.masksToBounds = true
view.layer.borderWidth = 3
view.layer.borderColor = Colors.tint.cgColor
return view
}()
let handleViewImage: UIImageView = {
let view = UIImageView()
view.translatesAutoresizingMaskIntoConstraints = false
view.image = UIImage(systemName: "chevron.right.2", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 40, weight: .bold)))?.withRenderingMode(.alwaysTemplate)
view.contentMode = .scaleAspectFit
view.tintColor = Colors.tint
return view
}()
let draggedView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = Colors.draggedBackground
view.layer.cornerRadius = 12
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.textColor = Colors.tint
label.font = .systemFont(ofSize: 24, weight: .semibold)
label.text = "Slide me!"
return label
}()
private var leadingThumbnailViewConstraint: NSLayoutConstraint?
private var panGestureRecognizer: UIPanGestureRecognizer!
weak var delegate: SlideToActionButtonDelegate?
private var xEndingPoint: CGFloat {
return (bounds.width - handleView.bounds.width)
}
private var isFinished = false
init() {
super.init(frame: .zero)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
func setup() {
backgroundColor = Colors.background
layer.cornerRadius = 12
addSubview(titleLabel)
addSubview(draggedView)
addSubview(handleView)
handleView.addSubview(handleViewImage)
//MARK: - Constraints
leadingThumbnailViewConstraint = handleView.leadingAnchor.constraint(equalTo: leadingAnchor)
NSLayoutConstraint.activate([
leadingThumbnailViewConstraint!,
handleView.topAnchor.constraint(equalTo: topAnchor),
handleView.bottomAnchor.constraint(equalTo: bottomAnchor),
handleView.widthAnchor.constraint(equalToConstant: 80),
draggedView.topAnchor.constraint(equalTo: topAnchor),
draggedView.bottomAnchor.constraint(equalTo: bottomAnchor),
draggedView.leadingAnchor.constraint(equalTo: leadingAnchor),
draggedView.trailingAnchor.constraint(equalTo: handleView.trailingAnchor),
handleViewImage.topAnchor.constraint(equalTo: handleView.topAnchor, constant: 10),
handleViewImage.bottomAnchor.constraint(equalTo: handleView.bottomAnchor, constant: -10),
handleViewImage.centerXAnchor.constraint(equalTo: handleView.centerXAnchor),
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor)
])
panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePanGesture(_:)))
panGestureRecognizer.minimumNumberOfTouches = 1
handleView.addGestureRecognizer(panGestureRecognizer)
}
@objc private func handlePanGesture(_ sender: UIPanGestureRecognizer) {
if isFinished { return }
let translatedPoint = sender.translation(in: self).x
switch sender.state {
case .changed:
if translatedPoint <= 0 {
updateHandleXPosition(0)
} else if translatedPoint >= xEndingPoint {
updateHandleXPosition(xEndingPoint)
} else {
updateHandleXPosition(translatedPoint)
}
case .ended:
if translatedPoint >= xEndingPoint {
self.updateHandleXPosition(xEndingPoint)
isFinished = true
delegate?.didFinish()
} else {
UIView.animate(withDuration: 1) {
self.reset()
}
}
default:
break
}
}
private func updateHandleXPosition(_ x: CGFloat) {
leadingThumbnailViewConstraint?.constant = x
}
func reset() {
isFinished = false
updateHandleXPosition(0)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment