我希望在用户点击我的视图导航栏标题时触发一个事件。关于是否可以访问UINavigationBar的标题视图以便将触摸事件与其连接,我有些困惑。这是可能的吗?
您可以向导航控制器的标题添加手势识别器以进行单击操作。 我发现在navigationBar的子视图中,标题的索引为1,左侧按钮的索引为0,右侧按钮的索引为2。
UITapGestureRecognizer *navSingleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(navSingleTap)];
navSingleTap.numberOfTapsRequired = 1;
[[self.navigationController.navigationBar.subviews objectAtIndex:1] setUserInteractionEnabled:YES];
[[self.navigationController.navigationBar.subviews objectAtIndex:1] addGestureRecognizer:navSingleTap];
然后在你的实现中的某个地方实现以下内容。
-(void)navSingleTap
所以你可以将其用于单击,或者在该标题上实现任何你想要的手势识别器。
UIButton *titleLabelButton = [UIButton buttonWithType:UIButtonTypeCustom];
[titleLabelButton setTitle:@"myTitle" forState:UIControlStateNormal];
titleLabelButton.frame = CGRectMake(0, 0, 70, 44);
titleLabelButton.font = [UIFont boldSystemFontOfSize:16];
[titleLabelButton addTarget:self action:@selector(didTapTitleView:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.titleView = titleLabelButton;
将那段代码放在设置标题的任何位置。然后我在其他地方进行了测试:
- (IBAction)didTapTitleView:(id) sender
{
NSLog(@"Title tap");
}
在控制台上记录了“标题点击”!
我处理这个问题的方式可能完全错误,但可能会给你提供一些想法。它确实帮助了我!不过可能有更好的方法。
其他答案对我都不太适用。我不是在现有的navigationBar子视图上添加手势,也不是替换titleView,而是简单地添加了一个清晰的UIView,覆盖了navigationBar的很大一部分...
- (void) setupNavbarGestureRecognizer {
// recognise taps on navigation bar to hide
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showHideNavbar)];
gestureRecognizer.numberOfTapsRequired = 1;
// create a view which covers most of the tap bar to
// manage the gestures - if we use the navigation bar
// it interferes with the nav buttons
CGRect frame = CGRectMake(self.view.frame.size.width/4, 0, self.view.frame.size.width/2, 44);
UIView *navBarTapView = [[UIView alloc] initWithFrame:frame];
[self.navigationController.navigationBar addSubview:navBarTapView];
navBarTapView.backgroundColor = [UIColor clearColor];
[navBarTapView setUserInteractionEnabled:YES];
[navBarTapView addGestureRecognizer:gestureRecognizer];
}
UINavigationItem
类参考文档有一个titleView
属性,您可以将其设置为自定义的UIView
。UIView
子类,然后在推送导航项时,将该项的titleView
属性设置为您子类的一个实例。UIView
可以有许多属性,包括用于替换标题的 UILabel
和一个用于“父”视图控制器的 UIViewController
属性,当您创建自定义视图的实例时设置。还要检查您的视图是否具有足够大小的框架。 - Alex Reynolds这是在Swift中最简单、最容易的解决方案,只需复制/粘贴并填写空白部分:
let navTapGesture = UITapGestureRecognizer(target: <#T##AnyObject?#>, action: <#T##Selector#>)
navigationItem.titleView.userInteractionEnabled = true
navigationItem.titleView.addGestureRecognizer(navTapGesture)
请确保在titleView
上将userInteractionEnabled
设置为true
,默认情况下它是关闭的。
UITapGestureRecognizer
附加到对应于titleView的导航栏子视图来完成。import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addTitleViewTapAction("tapped", numberOfTapsRequired: 3)
}
func addTitleViewTapAction(action: Selector, numberOfTapsRequired: Int) {
if let subviews = self.navigationController?.navigationBar.subviews {
for subview in subviews {
// the label title is a subview of UINavigationItemView
if let _ = subview.subviews.first as? UILabel {
let gesture = UITapGestureRecognizer(target: self, action: action)
gesture.numberOfTapsRequired = numberOfTapsRequired
subview.userInteractionEnabled = true
subview.addGestureRecognizer(gesture)
break
}
}
}
}
@objc func tapped() {
print("secret tap")
}
}
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSomething:)];
UILabel * titleView = [UILabel new];
titleView.text = @"Test";
[titleView sizeToFit];
titleView.userInteractionEnabled = YES;
[titleView addGestureRecognizer:tapGesture];
self.navigationItem.titleView = titleView;
titleView
,因为这意味着我不能再使用标准标题。另一方面,在向导航栏添加轻拍手势识别器时,我们必须确保它在点击工具栏按钮时不会触发。
这个解决方案可以同时解决这两个问题(需要添加到UINavigationBar
子类中):
- (void)awakeFromNib {
// put in -initWithFrame: if initialized manually
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(ft_titleTapped:)];
[self addGestureRecognizer:tap];
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
UIView *titleView = [self valueForKey:@"titleView"];
CGRect titleFrame = titleView.frame;
titleFrame.origin.y = 0; // expand to full height of navBar
titleFrame.size.height = self.frame.size.height;
return CGRectContainsPoint(titleFrame, [gestureRecognizer locationInView:self]);
}
- (void)ft_titleTapped:(UITapGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
// could add some checks here that the delegate is indeed a navigation controller
UIViewController<FTViewControllerAdditions> *viewController = (id)[((UINavigationController*)self.delegate) topViewController];
if ([viewController respondsToSelector:@selector(titleViewTapped:)]) {
[viewController titleViewTapped:self];
}
}
}
-titleViewTapped:
消息(如果已实现)。在UITableViewController
子类中,您可以像这样实现该方法以实现滚动到顶部功能:- (void)titleViewTapped:(id)sender {
[self.tableView setContentOffset:CGPointMake(0, -self.tableView.contentInset.top) animated:YES];
}
注意:我们正在使用未公开的-valueForKey:@"titleView"
方法来检索标题视图。这在技术上并不是使用私有API,但在将来的iOS版本中可能仍然会失败!
-[gestureRecognizerShouldBegin]
并将该类别导入到我的视图控制器中。 - Ken M. Haggerty在这个答案和这一个的基础上,我采用了下面的“函数式”方法,我不确定它是否更易读,但我更喜欢它而不是跳出循环。
if let navTitle = self.navigationController?.navigationBar.subviews.first(where: {$0.subviews.first is UILabel}) {
let gesture = UITapGestureRecognizer(target: self, action: action)
gesture.numberOfTapsRequired = numberOfTapsRequired
navTitle.isUserInteractionEnabled = true
navTitle.addGestureRecognizer(gesture)
}
setTintColor
和setTintAdjustmentMode
,但都不起作用。 - Adam CarterviewDidLoad
方法中,以便在深入导航栏后返回时使其正常工作,否则所有的导航栏项目都会在此之后激活它。 - James