UISwipeGestureRecognizer 无法在具有模糊效果的自定义 UIView 上一致触发

问题描述 投票:0回答:1

我正在为我的 iOS 应用程序构建一个自定义通知系统,其中临时通知视图显示在屏幕顶部。这些视图具有分层结构,其中包含用于模糊效果的 UIVisualEffectView 和包含图标和文本的内容视图。

我希望用户通过向下滑动来关闭通知。我成功地发现滑动手势已添加到视图中,但不知何故,没有检测到滑动,甚至没有检测到点击或平移手势。

滑动手势有时无法一致触发。下面是相关代码:

class NotificationViewController: UIViewController, UIGestureRecognizerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        // Show a notification after 1 second
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            self.showNotification(message: "Swipe down to dismiss!")
        }
    }
    
    func showNotification(message: String) {
        let notificationView = createNotificationView(message: message)
        view.addSubview(notificationView)
        positionNotification(notificationView, above: nil)
        
        // Automatically dismiss after 3 seconds
        DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
            self.dismissNotification(notificationView)
        }
    }
    
    private func createNotificationView(message: String) -> UIView {
        // Create the notification view
        let notificationView = UIView()
        notificationView.backgroundColor = .clear
        notificationView.layer.cornerRadius = 12
        notificationView.layer.borderWidth = 1
        notificationView.layer.borderColor = UIColor.darkGray.cgColor
        notificationView.translatesAutoresizingMaskIntoConstraints = false
        notificationView.isUserInteractionEnabled = true
        
        // Add blur effect
        let blurEffect = UIBlurEffect(style: .systemChromeMaterial)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.frame = notificationView.bounds
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        blurEffectView.isUserInteractionEnabled = false
        notificationView.addSubview(blurEffectView)
        
        // Add content to the blur effect view
        let label = UILabel()
        label.text = message
        label.textColor = .label
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        blurEffectView.contentView.addSubview(label)
        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: blurEffectView.contentView.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: blurEffectView.contentView.centerYAnchor)
        ])
        
        // Add swipe gesture recognizer
        let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(_:)))
        swipeGesture.direction = .down
        swipeGesture.delegate = self
        notificationView.addGestureRecognizer(swipeGesture)  
      
        return notificationView
    }
    
    private func positionNotification(_ notificationView: UIView, above previousNotificationView: UIView?) {
        notificationView.translatesAutoresizingMaskIntoConstraints = false
        if let previousView = previousNotificationView {
            NSLayoutConstraint.activate([
                notificationView.bottomAnchor.constraint(equalTo: previousView.topAnchor, constant: -10),
                notificationView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                notificationView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9),
                notificationView.heightAnchor.constraint(equalToConstant: 60)
            ])
        } else {
            NSLayoutConstraint.activate([
                notificationView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 60),
                notificationView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                notificationView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9),
                notificationView.heightAnchor.constraint(equalToConstant: 60)
            ])
        }
    }
    
    @objc private func handleSwipe(_ gesture: UISwipeGestureRecognizer) {
        guard let notificationView = gesture.view else { return }
        print("Swipe detected on notification!")
        dismissNotification(notificationView)
    }
    
    private func dismissNotification(_ notificationView: UIView) {
        UIView.animate(withDuration: 0.3, animations: {
            notificationView.alpha = 0
        }) { _ in
            notificationView.removeFromSuperview()
        }
    }

}

同样的方法也适用于其他视图,但它们是在父类级别声明的,而这个“通知视图”是在函数内初始化的,但值和其他一切都运行良好。这应该有效,所以我不确定我错过了什么。

希望得到一些建议。

ios swift uikit uigesturerecognizer uiswipegesturerecognizer
1个回答
0
投票

通过从 UIView 更改为 UIViewController 解决了该问题。


class NotificationViewController: UIViewController {
    private let message: String
    private let textColor: UIColor
    private let backgroundColor: UIColor
    private let iconName: String?
    private let iconColor: UIColor
    private let iconHeight: CGFloat
    private let displayDuration: Double
    
    init(message: String, textColor: UIColor, backgroundColor: UIColor, iconName: String?, iconColor: UIColor, iconHeight: CGFloat, displayDuration: Double) {
        self.message = message
        self.textColor = textColor
        self.backgroundColor = backgroundColor
        self.iconName = iconName
        self.iconColor = iconColor
        self.iconHeight = iconHeight
        self.displayDuration = displayDuration
        super.init(nibName: nil, bundle: nil)
        self.modalPresentationStyle = .overCurrentContext
        self.modalTransitionStyle = .crossDissolve
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.definesPresentationContext = true
        setupNotificationView()
    }
    
    private func setupNotificationView() {
        self.view.backgroundColor = .clear  // Make sure background is transparent
        
        // Create the notification content view
        let notificationContentView = UIView()
        notificationContentView.backgroundColor = .clear
        notificationContentView.layer.cornerRadius = ViewSetUpManager.mediumCornerRadius
        notificationContentView.layer.borderWidth = 1
        notificationContentView.layer.borderColor = UIColor.darkGray.cgColor
        notificationContentView.clipsToBounds = true
        notificationContentView.isUserInteractionEnabled = true
        
        // Add blur effect
        let blurEffect = UIBlurEffect(style: .systemChromeMaterial)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        notificationContentView.addSubview(blurEffectView)
        blurEffectView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        // Add icon and label
        let iconImageView = UIImageView()
        if let iconName = iconName {
            iconImageView.image = UIImage(systemName: iconName)
            iconImageView.contentMode = .scaleAspectFit
            iconImageView.tintColor = iconColor
            iconImageView.isUserInteractionEnabled = false
            blurEffectView.contentView.addSubview(iconImageView)
            iconImageView.snp.makeConstraints { make in
                make.leading.equalToSuperview().offset(16)
                make.centerY.equalToSuperview()
                make.width.height.equalTo(iconHeight)
            }
        }
        
        let label = UILabel()
        label.text = message
        label.font = UIFont.systemFont(ofSize: ViewSetUpManager.shared.genericTitleFontSize(), weight: .regular)
        label.textColor = textColor
        label.numberOfLines = 2
        label.textAlignment = .center
        label.adjustsFontSizeToFitWidth = true
        label.isUserInteractionEnabled = false
        blurEffectView.contentView.addSubview(label)
        label.snp.makeConstraints { make in
            make.leading.equalTo(iconImageView.snp.trailing).offset(8)
            make.trailing.equalToSuperview().inset(16)
            make.centerY.equalToSuperview()
        }
        
        // Add notificationContentView to self.view
        self.view.addSubview(notificationContentView)
        notificationContentView.snp.makeConstraints { make in
            make.bottom.equalTo(self.view.safeAreaLayoutGuide).offset(-(self.tabBarHeight() + 50))
            make.centerX.equalToSuperview()
            make.width.equalToSuperview().multipliedBy(0.9)
            make.height.greaterThanOrEqualTo(60)
        }
        
        // Add swipe gesture recognizer
        let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipeGesture(_:)))
        swipeGesture.direction = [.left, .down, .right]
        swipeGesture.delegate = self
        notificationContentView.addGestureRecognizer(swipeGesture)
        
        // Automatically dismiss after displayDuration
        DispatchQueue.main.asyncAfter(deadline: .now() + displayDuration) {
            self.dismiss(animated: true, completion: nil)
        }
    }
    
    private func tabBarHeight() -> CGFloat {
        return self.presentingViewController?.tabBarController?.tabBar.frame.height ?? 0
    }
    
    @objc private func handleSwipeGesture(_ gesture: UISwipeGestureRecognizer) {
        self.dismiss(animated: true, completion: nil)
    }
}

extension NotificationViewController: UIGestureRecognizerDelegate {
    // Implement delegate methods if necessary
}


© www.soinside.com 2019 - 2024. All rights reserved.