Как скрыть подпредставления вида (кнопка «Плавающее действие») от касания двух разных областей - PullRequest
0 голосов
/ 11 ноября 2019

Я создал кнопку с плавающим действием, которую я хотел бы отменить всеми кнопками действия, когда пользователь либо нажимает FAB, когда он открыт, либо когда пользователь нажимает в любом месте экрана, и FAB открыт. Также важно отметить, что FAB отображается поверх табличного представления, и я хочу сохранить возможность выбора ячеек табличного представления.

В моей реализации FAB я добавил цель к кнопке FAB, которую я использую, чтобы открывать и закрывать FAB, и я также реализовал tapGesture в viewController с табличным представлением так, чтобы при вызове жеста касания яможно открыть FAB, если он открыт.

Чтобы сделать эту работу, я провел небольшое исследование и обнаружил, что мне нужно установить

tap.cancelsTouchesInView = false

, чтобы tableViewСобытия продолжают работать. Однако побочным эффектом является то, что когда я нажимаю на фабрику, чтобы закрыть ее, запускаются два события - одно из tapGesture FAB, а другое - из кнопки-назначения, что приводит к тому, что FAB не закрывается, когда ты нажимаешь на него, если он открыт.

Существует ли более элегантный способ сделать так, чтобы FAB мог закрываться при касании, когда он открыт, а также иметь жест «Касание» в viewController, чтобы закрыть фабрику, когда он открыт, и пользователь нажимает в любом месте экрана.

Вот мой код:

ViewController:

    override func viewDidLoad() {
        super.viewDidLoad()

        let tap = UITapGestureRecognizer(target: self,
                                         action: #selector(self.dismissActionButtons(_:)))
        self.view.addGestureRecognizer(tap)

        tap.cancelsTouchesInView = false
        self.floatingActionButton.isHidden = true
    }

    @objc func dismissActionButtons(_ sender: UIButton) {
        if !floatingActionButton.actionButtonsCarousel.isHidden {
            self.floatingActionButton.animateActionButtonsDisappering()
        }
    }

Пользовательский FAB View:


    override init(frame: CGRect) {
        super.init(frame: .zero)

        actionButtonsCarousel.isHidden = true
        self.translatesAutoresizingMaskIntoConstraints = false

        self.mainButton.addTarget(self,
                                   action: #selector(ACTFAB.fabButtonAction(_:)),
                                   for: .touchUpInside)

    }
    @objc func fabButtonAction(_ sender: UIButton) {

        if self.actionButtonsCarousel.isHidden {
            self.animateActionButtonsAppering()
        } else {
            self.animateActionButtonsDisappering()
        }
    }

    func animateActionButtonsAppering() {
        self.actionButtonsCarousel.alpha = 0.0
        self.actionButtonsCarousel.isHidden = false

        UIView.transition(with: self, duration: 0.5, options: .preferredFramesPerSecond60, animations: {
            self.actionButtonsCarousel.alpha = 1.0
        })
        self.mainButton.setImage(UIImage(named: "fab-open-icon"), for: .normal)
    }

    func animateActionButtonsDisappering() {
        self.actionButtonsCarousel.alpha = 1.0
        self.actionButtonsCarousel.isHidden = true

        UIView.transition(with: self, duration: 0.3, options: .transitionCrossDissolve, animations: {
            self.actionButtonsCarousel.alpha = 0.0
        })
        self.mainButton.setImage(UIImage(named: "fab-closed-icon"), for: .normal)
    }

Два допустимых сценария:

1 FAB открыт -> нажмите FAB -> FAB закрывается

2 FAB открыт -> нажмите в любом месте, кроме FAB -> FAB закрывается

Сценарий № 1 не соответствует моему текущему коду.

Ответы [ 2 ]

1 голос
/ 11 ноября 2019

Если я правильно понимаю ваш вопрос, проблема в том, что нажатие FAB вызывает как действие кнопки, так и, когда вы передаете событие через базовый viewController, также происходит запуск gestRecogniser.

Я предполагаю, что действие кнопки является основным событием, и при его срабатывании вам необходимо остановить gestRecogniser. В gestRecogniser есть метод .location(in:), который позволяет вам получить первое местоположение касания (для tapGestureRecogniser) с точки зрения любого представления, а UIView имеет метод .point(inside: with:), который проверяет, является ли CGPoint (с точки зренияего собственное координатное пространство) находится внутри его границ. Следовательно, вы должны быть в состоянии сделать что-то подобное (из памяти и не скомпилировано, поэтому может потребоваться некоторая настройка, но, надеюсь, это должно помочь вам начать работу):

@objc func dismissActionButtons(_ sender: UIButton) {
  let tapPoint = sender.location(in: customFABview)
  if customFABview.point(inside: tapPoint, with: nil) && 
    !floatingActionButton.actionButtonsCarousel.isHidden {
            self.floatingActionButton.animateActionButtonsDisappering()
  }
}
0 голосов
/ 11 ноября 2019

Продолжая с ответа @ flanker, я создал логическое значение в fab для проверки того, происходит ли событие от tapGesture, затем я добавил его в условный оператор проверки следующим образом:

    var isComingFromGestureEvent: Bool = false

    @objc func fabButtonAction(_ sender: UIButton) {

        if self.actionButtonsCarousel.isHidden && !isComingFromGestureEvent {
            self.animateActionButtonsAppering()
        } else {
            self.animateActionButtonsDisappering()
        }
    }

В ViewController я тогдапросто использовал ответ Фланкера, чтобы установить логическое состояние следующим образом:

    var locationInView: CGPoint = CGPoint(x: 0, y: 0)

    override func viewDidLoad() {
        super.viewDidLoad()

        let tap = UITapGestureRecognizer(target: self,
                                         action: #selector(self.dismissActionButtons(_:)))
        self.view.addGestureRecognizer(tap)

        pointInView = tap.location(in: floatingActionButton)

        tap.cancelsTouchesInView = false
        self.floatingActionButton.isHidden = true
    }

    @objc func dismissActionButtons(_ sender: UIButton) {

        let tapPoint = pointInView
        if floatingActionButton.point(inside: tapPoint, with: nil) &&
          !floatingActionButton.actionButtonsCarousel.isHidden {

            self.floatingActionButton.isComingFromGestureEvent = true
            self.floatingActionButton.animateActionButtonsDisappering()

        } else {

            self.floatingActionButton.isComingFromGestureEvent = false

        }
    }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...