Skip to content

Instantly share code, notes, and snippets.

@cipolleschi
Last active November 16, 2020 10:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cipolleschi/d15767517d60a4b6bb96b85afb0eaf8a to your computer and use it in GitHub Desktop.
Save cipolleschi/d15767517d60a4b6bb96b85afb0eaf8a to your computer and use it in GitHub Desktop.
//
// GestureCode.swift
// Blending
//
// Created by Riccardo Cipolleschi on 14/11/2020.
//
import Foundation
import UIKit
// MARK: - View Model
struct VM {
var offset: CGPoint
}
// MARK: - View
class View: UIView {
var model: VM? {
didSet {
self.update(old: oldValue)
}
}
// MARK: Variable Declaration
private var ball = UIView()
// MARK: Interactions
var userDragged: ((CGPoint) -> ())?
// MARK: Initializers
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
self.style()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: Setup
private func setup() {
self.addSubview(self.ball)
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGestureRecognized))
self.ball.addGestureRecognizer(gestureRecognizer)
}
@objc private func panGestureRecognized(_ gestureRecognizer: UIPanGestureRecognizer) {
switch gestureRecognizer.state {
case .began:
let currentOffset = model?.offset ?? .zero
let translation = gestureRecognizer.translation(in: self)
let initialTranslation = currentOffset + translation
gestureRecognizer.setTranslation(initialTranslation, in: self)
self.userDragged?(initialTranslation)
break
case .changed:
let translation = gestureRecognizer.translation(in: self)
self.userDragged?(translation)
break
case .ended:
let translation = gestureRecognizer.translation(in: self)
self.userDragged?(translation)
break
default:
break
}
}
// MARK: Style
private func style() {
self.backgroundColor = .black
self.ball.backgroundColor = .red
self.ball.layer.cornerRadius = 25
}
// MARK: Update
private func update(old: VM?) {
self.setNeedsLayout()
}
// MARK: Layout
override func layoutSubviews() {
super.layoutSubviews()
self.ball.center = self.center + model?.offset
self.ball.bounds.size = CGSize(width: 50, height: 50)
}
}
// MARK: - VC
class VC: UIViewController {
// Helper to retrieve a correctly typed view
var rootView: View {
return self.view as! View
}
// This override of `loadView` creates the right type of view and sets the initial vm
override func loadView() {
super.loadView()
let view = View()
view.model = VM(offset: .zero)
self.view = view
}
// The `viewDidLoad` method is used to connect the interactions
override func viewDidLoad() {
super.viewDidLoad()
self.setupInteraction()
}
// It connects all the interactions from the View to the VC.
// Specifically, it receives the drag interaction in the view and updates the VM accordingly.
func setupInteraction() {
self.rootView.userDragged = { [unowned self] point in
self.rootView.model = VM(offset: point)
}
}
}
// MARK: - Helpers
extension CGPoint {
static func +(lhs: Self, rhs: Self?) -> CGPoint {
guard let right = rhs else {
return lhs
}
return .init(x: lhs.x + right.x, y: lhs.y + right.y)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment