我在我的應用程式中實作了一個彈出通知,以向用戶顯示資料是否已成功更新。
這個彈出視窗只是一個從 .xib 實體化的 UIView。這是 xib 檔案中元素層次結構的螢屏截圖:CLICK
如果用戶不想看到它在螢屏上顯示的完整時間,我還希望能夠刷出彈出視窗。為此,我實作了一個 UIGestureRecognizer:
private func configureTapGesture() {
guard let window = UIApplication.shared.windows.first(where: {$0.isKeyWindow}) else { return }
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
swipe.direction = .up
window.addGestureRecognizer(swipe)
}
@objc private func handleSwipes(_ sender:UISwipeGestureRecognizer) {
if sender.direction == .up {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveLinear) {
self.popupView.center.y -= 50
} completion: { _ in
self.popupView.removeFromSuperview()
}
self.isRemovedByTap = true
}
}
當我運行該應用程式時,它僅在我在任何地方但不在 popupView 內滑動時才有效。請檢查GIF:點擊
如果我將目標從self(Popup 類) 替換為popupView(UIVisualEffectView,這是您在 GIF 上看到的圓角矩形),那么我會收到一個錯誤unrecognized selector sent to instance
這是一個完整的自定義 Popup 類,我在其中初始化視圖、配置、影片并顯示它:
import UIKit
class PopupView: UIView {
@IBOutlet weak var popupView: UIVisualEffectView!
@IBOutlet weak var symbol: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var descriptionLabel: UILabel!
private var isRemovedByTap = false
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
private func configure() {
if let views = Bundle.main.loadNibNamed("PopupView", owner: self) {
guard let view = views.first as? UIView else { return }
view.frame = bounds
addSubview(view)
}
}
private func configurePopup() {
guard let window = UIApplication.shared.windows.first(where: {$0.isKeyWindow}) else { return }
popupView.layer.cornerRadius = 20
popupView.clipsToBounds = true
popupView.center.x = window.frame.midX
popupView.translatesAutoresizingMaskIntoConstraints = true
window.addSubview(popupView)
}
private func animatePopup() {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveLinear) {
self.popupView.center.y = 34
} completion: { _ in
UIView.animate(withDuration: 0.15, delay: 10.0, options: .curveLinear) {
self.popupView.center.y -= 50
} completion: { _ in
if !self.isRemovedByTap {
self.popupView.removeFromSuperview()
}
}
}
}
private func configureTapGesture() {
guard let window = UIApplication.shared.windows.first(where: {$0.isKeyWindow}) else { return }
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
swipe.direction = .up
window.addGestureRecognizer(swipe)
}
@objc private func handleSwipes(_ sender:UISwipeGestureRecognizer) {
if sender.direction == .up {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveLinear) {
self.popupView.center.y -= 50
} completion: { _ in
self.popupView.removeFromSuperview()
}
self.isRemovedByTap = true
}
}
func showPopup(title: String, message: String, symbol: UIImage) {
titleLabel.text = title
descriptionLabel.text = message
self.symbol.image = symbol
configurePopup()
animatePopup()
configureTapGesture()
}
}
What should I change to be able to swipe out only when inside the popupView rounded rectangle?
uj5u.com熱心網友回復:
幾個問題 - 沒有看到你的 xib 視圖層次結構,我無法完全測驗它,但它應該能讓你上路。
您正在將滑動手勢添加到視窗...
您無法在彈出視圖內滑動的原因是彈出視圖捕獲了觸摸手勢。如果您設定.isUserInteractionEnabled = false,您應該能夠在視圖內滑動。
如果您只想在視圖內滑動,請檢查滑動位置并查看視圖是否包含該點。
沿著這些思路:
@objc private func handleSwipes(_ sender:UISwipeGestureRecognizer) {
// may need to convert touch and frame
let loc = sender.location(in: self)
let r = popupView.frame
if sender.direction == .up, r.contains(loc) {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveLinear) {
self.popupView.center.y -= 50
} completion: { _ in
self.popupView.removeFromSuperview()
}
self.isRemovedByTap = true
}
}
您需要除錯框架和手勢坐標,以確保您檢查的是正確的區域。
編輯
要檢查滑動是否在 popupView 框架內,我們必須做幾件事......
添加一個新屬性——我會呼叫它yAdjustment——然后在你的animatePopup()func 中,將其設定為 popupView 的 y 原點:
var yAdjustment: CGFloat = 0
private func animatePopup() {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveLinear) {
self.popupView.center.y = 34
// save the top of the popupView frame
self.yAdjustment = self.popupView.frame.origin.y
} completion: { _ in
UIView.animate(withDuration: 0.15, delay: 10.0, options: .curveLinear) {
self.popupView.center.y -= 50
} completion: { _ in
if !self.isRemovedByTap {
self.popupView.removeFromSuperview()
}
}
}
}
然后,將您的滑動區域測驗更改為:
@objc private func handleSwipes(_ sender:UISwipeGestureRecognizer) {
// get location of swipe
var loc = sender.location(in: popupView)
// adjust the touch y
loc.y -= (yAdjustment - popupView.frame.origin.y)
// get the view bounds
let r = popupView.bounds
// only do this if
// swipe direct is up
// AND
// swipe location is inside popupView
if sender.direction == .up, r.contains(loc) {
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveLinear) {
self.popupView.center.y -= 50
} completion: { _ in
self.popupView.removeFromSuperview()
}
self.isRemovedByTap = true
}
}
我們必須“糾正”框架的原因......
When you write that chained animation block, this line:
self.popupView.center.y -= 50
is executed immediately -- the animation is simply delayed (by 10-seconds, in this case).
Normally, we would get the touch location in the view's frame and see if it is contained in the bounds.
In this case, though, because the view's frame has already been changed - even though we don't see it yet - we have to compensate for the new location.
uj5u.com熱心網友回復:
private func configureTapGesture() {
guard let window = UIApplication.shared.windows.first(where: {$0.isKeyWindow}) else { return }
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipes(_:)))
swipe.direction = .up
window.addGestureRecognizer(swipe)
// you also must add this and test it
self.addGestureRecognizer(swipe)
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/452646.html
標籤:ios swift popup uikit uiswipegesturerecognizer
