处理单个 UITabBarItem 上的长按
Handle long press on a single UITabBarItem
我在标签栏上使用长按手势。但我只需要一个特定标签栏项目的长按手势。
我该如何解决这个问题?我可以自定义标签栏中的长按手势吗?
您可以继承 UITabBarController
并向其 tabBar
添加 UILongPressGestureRecognizer
。作为手势识别器的代表,您可以选择何时检测到长按。由于标签栏项将在用户触摸后立即被选中,因此您可以使用 selectedItem
属性 来执行此检查。
@interface TabBarController () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) UILongPressGestureRecognizer *longPressRecognizer;
@end
@implementation TabBarController
- (void)viewDidLoad {
[super viewDidLoad];
self.longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(recognizerFired:)];
self.longPressRecognizer.delegate = self;
[self.tabBar addGestureRecognizer:self.longPressRecognizer];
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
// This will ensure the long press only occurs for the
// tab bar item which has it's tag set to 1.
// You can set this in Interface Builder or in code
// wherever you are creating your tabs.
if (self.tabBar.selectedItem.tag == 1) {
return YES;
}
else {
return NO;
}
}
- (void)recognizerFired:(UILongPressGestureRecognizer *)recognizer {
// Handle the long press...
}
@end
如果您只需要识别对其中一个 tabBar 项的长按,您可以在相应的 viewController 的 viewDidLoad
方法中执行此操作:
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector(handleLongPress:)];
[self.tabBarController.tabBar addGestureRecognizer: longPressGesture];
然后:
- (void)handleLongPress:(UILongPressGestureRecognizer *) recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
UITabBar *tabBar = ((UITabBar* )recognizer.view);
if (tabBar.selectedItem == self.tabBarItem) {
doSomethingVeryExciting();
}
}
}
如果你只是切换标签页,这不会触发。
下面是我如何使用 Swift 3:
protocol MyTabControllerProtocol: class {
func tabLongPressed()
}
class MyTabController: UITabBarController {
func viewDidLoad() {
super.viewDidLoad()
viewControllers = [
// add your view controllers for each tab bar item
// NOTE: if you want view controller to respond to long press, then it should extend MyTabControllerProtocol
]
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(astroButtonItemLongPressed(_:)))
tabBar.addGestureRecognizer(longPressRecognizer)
}
func astroButtonItemLongPressed(_ recognizer: UILongPressGestureRecognizer) {
guard recognizer.state == .began else { return }
guard let tabBar = recognizer.view as? UITabBar else { return }
guard let tabBarItems = tabBar.items else { return }
guard let viewControllers = viewControllers else { return }
guard tabBarItems.count == viewControllers.count else { return }
let loc = recognizer.location(in: tabBar)
for (index, item) in tabBarItems.enumerated() {
guard let view = item.value(forKey: "view") as? UIView else { continue }
guard view.frame.contains(loc) else { continue }
if let nc = viewControllers[index] as? UINavigationController {
if let vc = nc.viewControllers.first as? MyTabControllerProtocol {
vc.tabLongPressed()
}
} else if let vc = viewControllers[index] as? MyTabControllerProtocol {
vc.tabLongPressed()
}
break
}
}
}
我通过获取用户可以交互的特定 tabBarItem 视图并简单地向其添加长按手势来做到这一点。通过这种方式,您不必编写任何协议或将 TabBarViewController 子类化。
let longPressGestureRecognizer = UILongPressGestureRecognizer.init(target: self, action: #selector(longTap(_:)))
longPressGestureRecognizer.minimumPressDuration = 1.0
self.tabBarController?.orderedTabBarItemViews()[0].addGestureRecognizer(longPressGestureRecognizer)
关于获取 tabBarItemViews:
extension UITabBarController {
func orderedTabBarItemViews() -> [UIView] {
let interactionViews = tabBar.subviews.filter({[=11=].isUserInteractionEnabled})
return interactionViews.sorted(by: {[=11=].frame.minX < .frame.minX})
}
P.S。 :viewController,即"self"是tabBarController的第一项。
这是 swift 5 中的一个解决方案:
使用故事板或代码将长按手势识别器添加到 "Entire" 标签栏。
并且不要忘记让你的 ViewController 成为它的委托 .. 并实现下面的委托方法
检查传入触摸是否在标签栏子视图的 "one" 内.. 如果是 return true , else return false ..
以下是仅当我们在第一个选项卡上长按时才会让识别器触发的代码:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view?.isDescendant(of: tabBar.subviews[1]) == true {return true}
return false
}
注意:tabbar.subviews数组计数是项目数 + 1,这是标签栏的背景..所以如果你想要第一个项目的视图,你可以找到它并且索引 1 而不是 0
我在标签栏上使用长按手势。但我只需要一个特定标签栏项目的长按手势。
我该如何解决这个问题?我可以自定义标签栏中的长按手势吗?
您可以继承 UITabBarController
并向其 tabBar
添加 UILongPressGestureRecognizer
。作为手势识别器的代表,您可以选择何时检测到长按。由于标签栏项将在用户触摸后立即被选中,因此您可以使用 selectedItem
属性 来执行此检查。
@interface TabBarController () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) UILongPressGestureRecognizer *longPressRecognizer;
@end
@implementation TabBarController
- (void)viewDidLoad {
[super viewDidLoad];
self.longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(recognizerFired:)];
self.longPressRecognizer.delegate = self;
[self.tabBar addGestureRecognizer:self.longPressRecognizer];
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
// This will ensure the long press only occurs for the
// tab bar item which has it's tag set to 1.
// You can set this in Interface Builder or in code
// wherever you are creating your tabs.
if (self.tabBar.selectedItem.tag == 1) {
return YES;
}
else {
return NO;
}
}
- (void)recognizerFired:(UILongPressGestureRecognizer *)recognizer {
// Handle the long press...
}
@end
如果您只需要识别对其中一个 tabBar 项的长按,您可以在相应的 viewController 的 viewDidLoad
方法中执行此操作:
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector(handleLongPress:)];
[self.tabBarController.tabBar addGestureRecognizer: longPressGesture];
然后:
- (void)handleLongPress:(UILongPressGestureRecognizer *) recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
UITabBar *tabBar = ((UITabBar* )recognizer.view);
if (tabBar.selectedItem == self.tabBarItem) {
doSomethingVeryExciting();
}
}
}
如果你只是切换标签页,这不会触发。
下面是我如何使用 Swift 3:
protocol MyTabControllerProtocol: class {
func tabLongPressed()
}
class MyTabController: UITabBarController {
func viewDidLoad() {
super.viewDidLoad()
viewControllers = [
// add your view controllers for each tab bar item
// NOTE: if you want view controller to respond to long press, then it should extend MyTabControllerProtocol
]
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(astroButtonItemLongPressed(_:)))
tabBar.addGestureRecognizer(longPressRecognizer)
}
func astroButtonItemLongPressed(_ recognizer: UILongPressGestureRecognizer) {
guard recognizer.state == .began else { return }
guard let tabBar = recognizer.view as? UITabBar else { return }
guard let tabBarItems = tabBar.items else { return }
guard let viewControllers = viewControllers else { return }
guard tabBarItems.count == viewControllers.count else { return }
let loc = recognizer.location(in: tabBar)
for (index, item) in tabBarItems.enumerated() {
guard let view = item.value(forKey: "view") as? UIView else { continue }
guard view.frame.contains(loc) else { continue }
if let nc = viewControllers[index] as? UINavigationController {
if let vc = nc.viewControllers.first as? MyTabControllerProtocol {
vc.tabLongPressed()
}
} else if let vc = viewControllers[index] as? MyTabControllerProtocol {
vc.tabLongPressed()
}
break
}
}
}
我通过获取用户可以交互的特定 tabBarItem 视图并简单地向其添加长按手势来做到这一点。通过这种方式,您不必编写任何协议或将 TabBarViewController 子类化。
let longPressGestureRecognizer = UILongPressGestureRecognizer.init(target: self, action: #selector(longTap(_:)))
longPressGestureRecognizer.minimumPressDuration = 1.0
self.tabBarController?.orderedTabBarItemViews()[0].addGestureRecognizer(longPressGestureRecognizer)
关于获取 tabBarItemViews:
extension UITabBarController {
func orderedTabBarItemViews() -> [UIView] {
let interactionViews = tabBar.subviews.filter({[=11=].isUserInteractionEnabled})
return interactionViews.sorted(by: {[=11=].frame.minX < .frame.minX})
}
P.S。 :viewController,即"self"是tabBarController的第一项。
这是 swift 5 中的一个解决方案: 使用故事板或代码将长按手势识别器添加到 "Entire" 标签栏。 并且不要忘记让你的 ViewController 成为它的委托 .. 并实现下面的委托方法 检查传入触摸是否在标签栏子视图的 "one" 内.. 如果是 return true , else return false .. 以下是仅当我们在第一个选项卡上长按时才会让识别器触发的代码:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view?.isDescendant(of: tabBar.subviews[1]) == true {return true}
return false
}
注意:tabbar.subviews数组计数是项目数 + 1,这是标签栏的背景..所以如果你想要第一个项目的视图,你可以找到它并且索引 1 而不是 0