如何隐藏视图的子视图(浮动操作按钮)以防止点击两个不同的区域
How to hide a view's subviews (Floating Action button) from tapping two different areas
我创建了一个浮动操作按钮,当用户在 FAB 打开时点击它,或者当用户点击屏幕上的任意位置并且 FAB 打开时,我想关闭所有操作按钮。同样重要的是要注意 FAB 正在显示在 tableview 上,我想保留 select tableview 单元格的能力。
在我的 FAB 实现中,我向 FAB 按钮添加了一个目标,我用它来打开和关闭 FAB,我还在 viewController 上用 tableview 实现了一个 tapGesture,这样当点击手势时被调用我可以关闭 FAB 如果打开。
为了完成这项工作,我做了一些研究,发现我必须设置
tap.cancelsTouchesInView = false
以便 tableView 事件继续工作。然而,副作用是,当我点击 fab 关闭它时,会触发两个事件,一个是从 FAB 的 tapGesture 触发,另一个是从按钮目标触发,这会导致 FAB 在打开时点击它时不会关闭。
是否有更优雅的方式使 FAB 在打开时能够在点击时关闭,并且在 viewController 上使用点击手势在 fab 打开并且用户点击任意位置时关闭 fab屏幕。
这是我的一些代码:
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 视图:
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 is open -> click FAB -> FAB closes
2 FAB is open -> click anywhere other than FAB -> FAB closes
场景 1 因我当前的代码而失败。
如果我正确理解你的问题,问题是点击 FAB 会导致按钮的动作被触发,而且当你将事件传递给底层 viewController 时,gestureRecogniser 也会触发也。
我假设按钮操作是主要事件,当它触发时您需要停止 gestureRecogniser。 gestureRecogniser 有一个 .location(in:)
方法,它允许您根据任何视图获取第一个点击位置(对于 tapGestureRecogniser),UIView
有一个 .point(inside: with:)
方法来检查 CGPoint
(根据它自己的坐标 space)在它的范围内。因此你应该能够做这样的事情(从内存而不是编译,所以可能需要一些调整但希望它能让你开始):
@objc func dismissActionButtons(_ sender: UIButton) {
let tapPoint = sender.location(in: customFABview)
if customFABview.point(inside: tapPoint, with: nil) &&
!floatingActionButton.actionButtonsCarousel.isHidden {
self.floatingActionButton.animateActionButtonsDisappering()
}
}
继续@flanker 的回答,我在 fab 中创建了一个布尔值来检查事件是否来自 tapGesture 然后我将它添加到检查条件语句中,如下所示:
var isComingFromGestureEvent: Bool = false
@objc func fabButtonAction(_ sender: UIButton) {
if self.actionButtonsCarousel.isHidden && !isComingFromGestureEvent {
self.animateActionButtonsAppering()
} else {
self.animateActionButtonsDisappering()
}
}
在 ViewController 中,我只是使用 flanker 的答案来设置布尔状态,如下所示:
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
}
}
我创建了一个浮动操作按钮,当用户在 FAB 打开时点击它,或者当用户点击屏幕上的任意位置并且 FAB 打开时,我想关闭所有操作按钮。同样重要的是要注意 FAB 正在显示在 tableview 上,我想保留 select tableview 单元格的能力。
在我的 FAB 实现中,我向 FAB 按钮添加了一个目标,我用它来打开和关闭 FAB,我还在 viewController 上用 tableview 实现了一个 tapGesture,这样当点击手势时被调用我可以关闭 FAB 如果打开。
为了完成这项工作,我做了一些研究,发现我必须设置
tap.cancelsTouchesInView = false
以便 tableView 事件继续工作。然而,副作用是,当我点击 fab 关闭它时,会触发两个事件,一个是从 FAB 的 tapGesture 触发,另一个是从按钮目标触发,这会导致 FAB 在打开时点击它时不会关闭。
是否有更优雅的方式使 FAB 在打开时能够在点击时关闭,并且在 viewController 上使用点击手势在 fab 打开并且用户点击任意位置时关闭 fab屏幕。
这是我的一些代码:
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 视图:
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 is open -> click FAB -> FAB closes
2 FAB is open -> click anywhere other than FAB -> FAB closes
场景 1 因我当前的代码而失败。
如果我正确理解你的问题,问题是点击 FAB 会导致按钮的动作被触发,而且当你将事件传递给底层 viewController 时,gestureRecogniser 也会触发也。
我假设按钮操作是主要事件,当它触发时您需要停止 gestureRecogniser。 gestureRecogniser 有一个 .location(in:)
方法,它允许您根据任何视图获取第一个点击位置(对于 tapGestureRecogniser),UIView
有一个 .point(inside: with:)
方法来检查 CGPoint
(根据它自己的坐标 space)在它的范围内。因此你应该能够做这样的事情(从内存而不是编译,所以可能需要一些调整但希望它能让你开始):
@objc func dismissActionButtons(_ sender: UIButton) {
let tapPoint = sender.location(in: customFABview)
if customFABview.point(inside: tapPoint, with: nil) &&
!floatingActionButton.actionButtonsCarousel.isHidden {
self.floatingActionButton.animateActionButtonsDisappering()
}
}
继续@flanker 的回答,我在 fab 中创建了一个布尔值来检查事件是否来自 tapGesture 然后我将它添加到检查条件语句中,如下所示:
var isComingFromGestureEvent: Bool = false
@objc func fabButtonAction(_ sender: UIButton) {
if self.actionButtonsCarousel.isHidden && !isComingFromGestureEvent {
self.animateActionButtonsAppering()
} else {
self.animateActionButtonsDisappering()
}
}
在 ViewController 中,我只是使用 flanker 的答案来设置布尔状态,如下所示:
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
}
}