Почему мой распознаватель uitapgesturer не вызывается при анимации UIView?

#ios #swift

Вопрос:

Я сделал тост с UIImageView изображением в нем, что я хочу делать, так это каждый раз, когда пользователь нажимает на изображение, тост отключается сам по себе. Естественно, я настроил a UITapGestureRecognizer для своего представления изображения, но функция селектора не вызывается. Вот что я сделал:

 class ToastView: UIView {

    private var icon: UIImageView!

    init() {
        super.init(frame: .zero)
        setupViews()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupViews()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        setupConstraints()
    }

    private func setupViews() {
        translatesAutoresizingMaskIntoConstraints = false
        layer.cornerRadius = 8
        isUserInteractionEnabled = true
  
        icon = UIImageView()
        icon.translatesAutoresizingMaskIntoConstraints = false
        icon.image = UIImage(named: "someImage")
        icon.isUserInteractionEnabled = true
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(iconHandler))
        icon.addGestureRecognizer(tapGesture)
        addSubview(icon)
    }

    private func setupConstraints() {
        NSLayoutConstraint.activate([
            topAnchor.constraint(equalTo: superview!.topAnchor, constant: 55),
            leadingAnchor.constraint(equalTo: superview!.leadingAnchor, constant: 16),
            trailingAnchor.constraint(equalTo: superview!.trailingAnchor, constant: -16),
            icon.heightAnchor.constraint(equalToConstant: 16),
            icon.widthAnchor.constraint(equalToConstant: 16),
            icon.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            icon.centerYAnchor.constraint(equalTo: centerYAnchor),
        ])
    }

    @objc private func iconHandler(_ sender: UITapGestureRecognizer) {
        // This function is not called
        print("handle icon")
    }
}
 

После некоторых исследований я попытался ToastView использовать распознаватель жестов вместо представления изображения. Поэтому я дал распознаватель жестов нажатия при показе тоста в моем пользовательском UIViewController классе, как это:

 class CustomViewController: UIViewController {
    private var isShowingToast: Bool = false
    private lazy var toast: ToastView = {
        let toast = ToastView()
        toast.isUserInteractionEnabled = true
        toast.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissToast)))
        return toast
    }()

    func showToastWithMessage() {
        if !isShowingToast {
            view.addSubview(toast)
            UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
                self?.toast.alpha = 1
                self?.toast.frame.origin.y  = 10
                self?.isShowingToast = true
            }, completion: { _ in
                UIView.animate(withDuration: 0.5, delay: 5.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
                    self?.toast.alpha = 0
                    self?.toast.frame.origin.y -= 10
                }, completion: { [weak self] _ in
                    self?.isShowingToast = false
                    self?.toast.removeFromSuperview()
                })
            })
        }
    }
    
    @objc private func dismissToast() {
        // This functions does not get called as well
        print("dismiss")
    }
}
 

К сожалению, функция «отклонить» не выводится на консоль. Есть ли в любом случае способ решить эту проблему?

Комментарии:

1. Что делать, если вы удалите ключевое private слово из dismissToast ? Не могли бы вы проверить, исправляет ли это проблему? Тнх.

2. Что это такое? значок = UIImageView() У него нет рамки?

3. @matt я только что попробовал, к сожалению, функция все еще не вызывается

4. Ознакомьтесь с моей статьей, в ней рассматриваются общие причины: biteinteractive.com/…

5. @llehcram Во время анимации не будет никакого взаимодействия с пользователем. в этом и будет проблема. поставьте некоторую задержку перед запуском второй анимации.

Ответ №1:

Похоже, это происходит из-за вашей анимации. Просмотр все время находится в состоянии анимации и блокирует жест касания. Вы можете попробовать вызвать его с задержкой вместо добавления задержки для вашей анимации.

 func showToastWithMessage() {
    if !isShowingToast {
        view.addSubview(toast)
        UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
            self?.toast.alpha = 1
            self?.toast.frame.origin.y  = 10
            self?.isShowingToast = true
        }, completion: { _ in
            print("Completion")
        })

        DispatchQueue.main.asyncAfter(deadline: .now()   5) {
            UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
                self?.toast.alpha = 0
                self?.toast.frame.origin.y -= 10
            }, completion: { [weak self] _ in
                self?.isShowingToast = false
                self?.toast.removeFromSuperview()
            })
        }

    }
}
 

Таким образом, просмотр будет анимировать статус через 5 секунд, а не с задержкой в 5 секунд.

Ответ №2:

Вот как выглядит ваш контроллер:

 class CustomViewController: UIViewController {

private var isShowingToast: Bool = false
 lazy var toast: ToastView = {
    let toast = ToastView()
    toast.isUserInteractionEnabled = true
    toast.backgroundColor = .red
    toast.translatesAutoresizingMaskIntoConstraints = false 
    toast.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissToast)))
    return toast
}()

override func viewDidLoad() {
    super.viewDidLoad()
    // Add Toast constraints
    view.addSubview(toast)
    toast.heightAnchor.constraint(equalToConstant: 200).isActive = true
    toast.widthAnchor.constraint(equalTo: toast.heightAnchor).isActive = true
    toast.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    toast.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}

func showToastWithMessage() {
    if !isShowingToast {
        view.addSubview(toast)
        UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
            self?.toast.alpha = 1
            self?.toast.frame.origin.y  = 10
            self?.isShowingToast = true
        }, completion: { _ in
            UIView.animate(withDuration: 0.5, delay: 5.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
                self?.toast.alpha = 0
                self?.toast.frame.origin.y -= 10
            }, completion: { [weak self] _ in
                self?.isShowingToast = false
                self?.toast.removeFromSuperview()
            })
        })
    }
}

@objc private func dismissToast() {
    // This functions does not get called as well
    print("dismiss")
 }
}
 

И это твой класс:

 class ToastView: UIView {

private var icon = UIImageView()

init() {
    super.init(frame: .zero)
    setupViews()
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    setupViews()
}

override func layoutSubviews() {
    super.layoutSubviews()
    setupConstraints()
}

private func setupViews() {
    translatesAutoresizingMaskIntoConstraints = false
    layer.cornerRadius = 8
    isUserInteractionEnabled = true

    icon.translatesAutoresizingMaskIntoConstraints = false
    icon.image = UIImage(named: "profilo")?.withRenderingMode(.alwaysOriginal) //put your image here
    icon.isUserInteractionEnabled = true
    icon.layer.cornerRadius = 8
    icon.layer.masksToBounds = true //set image masked round corner
    icon.clipsToBounds = true
    icon.contentMode = .scaleAspectFill //set image content mode
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(iconHandler))
    icon.addGestureRecognizer(tapGesture)
}

private func setupConstraints() {
    // Setup the constraints for the subviews
    addSubview(icon)
    icon.topAnchor.constraint(equalTo: topAnchor).isActive = true
    icon.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
    icon.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
    icon.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}

@objc private func iconHandler(_ sender: UITapGestureRecognizer) {
    // This function is not called
    print("handle icon")
 }
}
 

это и есть результат:

введите описание изображения здесь