Когда я начинаю перетаскивать изображение, оно запускает таймер, но каждую секунду (когда таймер повторяется) перетаскивание прерывается, и изображение появляется в начальной позиции в течение миллисекунды.Вот видео .Если я удаляю таймер, то перетаскивание работает должным образом.
Я создал пользовательский класс для перетаскиваемого изображения (DragItem), в котором при касании изображения публикуется уведомление, которое запускает таймер на ViewController.
Я предполагаю, что этот сбой может быть связан с RunLoop.main.add (timer, forMode: RunLoop.Mode.common) , однако я не могу понять, как это исправить,Есть идеи?
Вот наиболее близкие темы, которые мне удалось найти: Таймер не работает при перетаскивании и Приостановка таймера при прокрутке
DragItem: класс UIImageView
var dragItemOrigin: CGPoint!
var dropTaget: UIView?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "touchedDragItem"), object: nil)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let location = touch.location(in: self.superview)
self.center = location
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
UIView.animate(withDuration: 0.3, animations: {
if let touch = touches.first, let target = self.dropTaget {
let position = touch.location(in: self.superview)
if target.frame.contains(position) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onTargetDropped"), object: nil)
}
}
})
}
ViewController
var counter = 4.0
var timer: Timer!
var isTimerRunning = false
var MAX_PENALTIES = 3
var penalties: Int = 0
let dragItemInCode: DragItem = {
let imageView = DragItem(frame: CGRect.zero)
imageView.image = UIImage(named: "Oval1.png")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.isUserInteractionEnabled = true
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(dragItemInCode)
counter = 4
view.bringSubviewToFront(dragItemInCode)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.dragItemTouched(_:)), name:NSNotification.Name(rawValue: "touchedDragItem"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.dragItemDroppedOnDropItem(_:)), name:NSNotification.Name(rawValue: "onTargetDropped"), object: nil)
setupLayout()
}
private func setupLayout() {
dragItemInCode.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
dragItemInCode.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
dragItemInCode.widthAnchor.constraint(equalToConstant: 35).isActive = true
dragItemInCode.heightAnchor.constraint(equalToConstant: 35).isActive = true
//dragItemInCode.layoutIfNeeded()
}
@objc func dragItemTouched(_ sender: NSNotification) {
print("item touched")
startTimer()
}
func startTimer() {
timer = Timer(timeInterval: 4, target: self, selector: #selector(ViewController.changeGameState), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}
@objc func dragItemDroppedOnDropItem(_ sender: NSNotification) {
print("item dropped")
}
func timerLabelUpdates() {
timerLbl.text = String(format: "%.1f", counter)
if counter <= 0 {
penalties += 1
} else {
self.counter -= 0.1
}
}
@objc func changeGameState() {
timerLbl.text = String(format: "%.1f", counter)
if counter > 0 {
self.counter -= 1
} else {
gameOver()
}
func gameOver() {
timer.invalidate()
dropItemLbl.playDeathAnimation()
UIView.animate(withDuration: 1, delay: 0.5, options: .curveEaseInOut, animations: {
Vibration.error.vibrate()
self.dragItemInCode.alpha = 0
self.explosion()
}, completion: nil)
}
func explosion() {
let emitter = ExplodeView.get(with: #imageLiteral(resourceName: "particle"))
emitter.emitterPosition = CGPoint(x: dragItemInCode.frame.width / 2, y: dragItemInCode.frame.height/2)
emitter.emitterSize = dragItemInCode.bounds.size
dragItemInCode.layer.addSublayer(emitter)
}
}