I'd like to move a simple, small UIView around the screen and 'drop' it off at any location on the screen, but accurately. Simply lifting your finger from the screen does not have the desired effect as there is always some movement upon lifting your finger, resulting in the object not being in the required location. What I'm looking for is some way to count down a specified number of milliseconds AFTER holding/pausing at the desired location and then have some mechanism ENDING my touches/gesture so the object is placed EXACTLY where I want it.
I've been reasonably successful with touchesBegan/Moved/Ended, but even though I called the touchesEnded method the touches never really end as I can still drag around the object on the screen and relocate it - not what I want.
import UIKit
class ViewController: UIViewController {
let greenDot : UIView = {
let greenDot = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
greenDot.backgroundColor = .green
greenDot.layer.cornerRadius = greenDot.bounds.height / 2
return greenDot
}()
var timer : Timer?
var lastTouch = Set<UITouch>()
var lastTouchEvent: UIEvent?
override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
print(touch.location(in: view))
greenDot.center = touch.location(in: view)
view.addSubview(greenDot)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
print(touch.location(in: view))
if timer != nil { timer?.invalidate() }
greenDot.center = touch.location(in: view)
view.addSubview(greenDot)
lastTouch = touches
lastTouchEvent = event
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(stopTouches), userInfo: nil, repeats: false)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
timer?.invalidate()
print("Touches Ended @: \(touch.location(in: view))")
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Cancelling touch")
}
@objc func stopTouches() {
touchesEnded(lastTouch, with: lastTouchEvent)
// touchesCancelled(lastTouch, with: lastTouchEvent)
// view.resignFirstResponder()
}
}
With UIGestures I have tried with the UILongPressGestureRecognizer, but I don't know how to 'end' with a long-press. Do I use 2 long-presses in sequence - one to start the movement and another to end the movement? I like the longPress since it is continuous and I can thus pan with it.
import UIKit
class ViewController: UIViewController {
let greenDot : UIView = {
let dot = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
dot.backgroundColor = .green
dot.layer.cornerRadius = dot.frame.width/2
return dot
}()
override func viewDidLoad() {
super.viewDidLoad()
let longPress1 = UILongPressGestureRecognizer(target: self, action: #selector(press1))
longPress1.minimumPressDuration = 0.2
view.addGestureRecognizer(longPress1)
}
@objc func press1(_ sender: UILongPressGestureRecognizer) {
let newLocation = sender.location(in: view)
greenDot.backgroundColor = .green
greenDot.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
greenDot.center = CGPoint(x: newLocation.x, y: newLocation.y - 40)
if sender.state == .ended {
greenDot.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
greenDot.center = CGPoint(x: newLocation.x, y: newLocation.y - 40)
greenDot.backgroundColor = .purple
}
view.addSubview(greenDot)
}
}
So in conclusion: I'm looking for a method to place an object, which I am moving around on the screen with my finger, accurately.
Any help in this regard will be greatly appreciated.