让用户能够在临时 UIView 上向下滑动
Have User be able to Swipe Down on temporary UIView
我希望能够让用户向下滑动以关闭从底部进入的临时通知。
代码如下所示:
func showAnimationToast(...) {
let toastView = UIView(frame: CGRect(x: 10, y: view.frame.size.height - view.safeAreaInsets.bottom, width: view.frame.size.width - 20, height: 60))
...
toastView.tag = 1474
let animationView = AnimationView(name: animationName)
...
toastView.addSubview(animationView)
let messageLabel = UILabel(frame: CGRect(x: toastView.frame.size.height, y: 5, width: toastView.frame.size.width - toastView.frame.size.height, height: 50))
...
toastView.addSubview(messageLabel)
toastView.isUserInteractionAvailable = true
我尝试将 UISwipeGestureRecognizer 添加到 toastView
,但从未成功。我什至尝试了简单的 UITapGestureRecognizer,但它仍然没有用。
这是我尝试过的:
//Let Swipe Down Dismiss. Does not work
let swipeDownGesture = UISwipeGestureRecognizer(target: self, action: #selector(dismissToast(_:)))
swipeDownGesture.direction = .down
toastView.addGestureRecognizer(swipeDownGesture)
//Show animation
UIView.animate(withDuration: 0.2, delay: 0, animations: {
toastView.frame.origin.y = self.view.frame.size.height - self.view.safeAreaInsets.bottom - 70
}, completion: {_ in
animationView.play()
})
//Remove after specified time
UIView.animate(withDuration: 0.2, delay: duration, animations: {
toastView.center.y = self.view.frame.size.height + 50
}, completion: {_ in
toastView.removeFromSuperview()
})
}
@objc func dismissToast(_ sender: UIGestureRecognizer) {
print("dismiss")
let toastView = view.subviews.filter { view in
if view.tag == 1474 /*toastView*/ tag{
return true
}
return false
}.last!
UIView.animate(withDuration: 0.2, delay: 0, animations: {
toastView.center.y = self.view.frame.size.height + 50
}, completion: {_ in
toastView.removeFromSuperview()
})
}
问题似乎是在视图等待动画播放时(在“延迟”期间),它无法接收用户交互。
解决此问题的一种方法是不使用 delay
参数,而是使用 DispatchQueue.main.asyncAfter
:
UIView.animate(withDuration: 0.2, delay: 0, options: [.allowUserInteraction], animations: {
toastView.frame.origin.y = self.view.frame.size.height - self.view.safeAreaInsets.bottom - 70
}, completion: {_ in
DispatchQueue.main.asyncAfter(deadline: .now() + duration + 0.2) {
UIView.animate(withDuration: 0.2, delay: 0, animations: {
toastView.center.y = self.view.frame.size.height + 50
}, completion: {_ in
toastView.removeFromSuperview()
})
}
})
我希望能够让用户向下滑动以关闭从底部进入的临时通知。
代码如下所示:
func showAnimationToast(...) {
let toastView = UIView(frame: CGRect(x: 10, y: view.frame.size.height - view.safeAreaInsets.bottom, width: view.frame.size.width - 20, height: 60))
...
toastView.tag = 1474
let animationView = AnimationView(name: animationName)
...
toastView.addSubview(animationView)
let messageLabel = UILabel(frame: CGRect(x: toastView.frame.size.height, y: 5, width: toastView.frame.size.width - toastView.frame.size.height, height: 50))
...
toastView.addSubview(messageLabel)
toastView.isUserInteractionAvailable = true
我尝试将 UISwipeGestureRecognizer 添加到 toastView
,但从未成功。我什至尝试了简单的 UITapGestureRecognizer,但它仍然没有用。
这是我尝试过的:
//Let Swipe Down Dismiss. Does not work
let swipeDownGesture = UISwipeGestureRecognizer(target: self, action: #selector(dismissToast(_:)))
swipeDownGesture.direction = .down
toastView.addGestureRecognizer(swipeDownGesture)
//Show animation
UIView.animate(withDuration: 0.2, delay: 0, animations: {
toastView.frame.origin.y = self.view.frame.size.height - self.view.safeAreaInsets.bottom - 70
}, completion: {_ in
animationView.play()
})
//Remove after specified time
UIView.animate(withDuration: 0.2, delay: duration, animations: {
toastView.center.y = self.view.frame.size.height + 50
}, completion: {_ in
toastView.removeFromSuperview()
})
}
@objc func dismissToast(_ sender: UIGestureRecognizer) {
print("dismiss")
let toastView = view.subviews.filter { view in
if view.tag == 1474 /*toastView*/ tag{
return true
}
return false
}.last!
UIView.animate(withDuration: 0.2, delay: 0, animations: {
toastView.center.y = self.view.frame.size.height + 50
}, completion: {_ in
toastView.removeFromSuperview()
})
}
问题似乎是在视图等待动画播放时(在“延迟”期间),它无法接收用户交互。
解决此问题的一种方法是不使用 delay
参数,而是使用 DispatchQueue.main.asyncAfter
:
UIView.animate(withDuration: 0.2, delay: 0, options: [.allowUserInteraction], animations: {
toastView.frame.origin.y = self.view.frame.size.height - self.view.safeAreaInsets.bottom - 70
}, completion: {_ in
DispatchQueue.main.asyncAfter(deadline: .now() + duration + 0.2) {
UIView.animate(withDuration: 0.2, delay: 0, animations: {
toastView.center.y = self.view.frame.size.height + 50
}, completion: {_ in
toastView.removeFromSuperview()
})
}
})