第一个问题是:
当你有一个tableView如何实现用户可以点击导航条滚动到顶部
解决方案:
- (void)viewDidLoad {
UITapGestureRecognizer* tapRecon = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(navigationBarDoubleTap:)];
tapRecon.numberOfTapsRequired = 2;
[navController.navigationBar addGestureRecognizer:tapRecon];
[tapRecon release];
}
- (void)navigationBarDoubleTap:(UIGestureRecognizer*)recognizer {
[tableView setContentOffset:CGPointMake(0,0) animated:YES];
}
效果很好!
但是Drarok指出了一个问题:
这种方法只有在你没有后退按钮或rightBarButtonItem的情况下才可行。它们的点击事件被手势识别器
覆盖。我的问题:
我怎么能有很好的功能,我的导航栏是可点击的,但仍然能够使用后退按钮在我的应用程序?
所以要么找到一个不覆盖后退按钮的不同解决方案,要么找到一个让后退按钮重新工作的解决方案:)
我没有使用位置视图,而是通过检查UITouch的类来解决这个问题。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return (![[[touch view] class] isSubclassOfClass:[UIControl class]]);
}
请注意,导航按钮的类型是UINavigationButton
,它没有公开,因此子类检查。
此方法在您指定为手势识别器委托的类中。如果你刚刚开始使用手势识别器,请注意委托是与目标分开设置的。
UIGestureRecognizerDelegate有一个叫做"gestureRecognizer:shouldReceiveTouch"的方法。如果你能指出触摸视图是否是按钮,只要让它返回"NO"否则返回"YES"就可以了
UIGestureRecognizer
也有一个属性@property(nonatomic) BOOL cancelsTouchesInView
。来自文档:A Boolean value affecting whether touches are delivered to a view when a gesture is recognized.
所以如果你只做
tapRecon.cancelsTouchesInView = NO;
这可能是一个更简单的解决方案,这取决于您的用例。这是我在我的应用程序中做的。
当按下导航栏中的按钮时,它的动作被执行(如期望的那样),但UIGestureRecognizer
的动作也被执行。如果你不介意的话,这是我能想到的最简单的解决方法。
iOS7版本:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
CGPoint point = [touch locationInView:touch.view];
UINavigationBar *naviagationBar = (UINavigationBar *)touch.view;
NSString *navigationItemViewClass = [NSString stringWithFormat:@"UINavigationItem%@%@",@"Button",@"View"];
for (id subview in naviagationBar.subviews) {
if (([subview isKindOfClass:[UIControl class]] ||
[subview isKindOfClass:NSClassFromString(navigationItemViewClass)]) &&
[subview pointInside:point withEvent:nil]) {
return NO;
}
}
return YES;
}
编辑:在后退按钮手势的角落的东西仍然被覆盖,所以你这个代码代替pointInside:withEvent
:
CGRectContainsPoint((CGRect){ .origin = subview.frame.origin, .size = CGSizeMake(subview.frame.size.width + 16, subview.frame.size.height)}, point)
Xamarin。iOS没有在私有API中为Objective-C类公开c#包装器,所以上面@ben-flynn建议的简洁的子类检查在这里不起作用。
一个比较hack的解决方法是检查视图的Description
字段:
navigationTitleTap = new UITapGestureRecognizer (tap => DidTapNavigationTitle());
navigationTitleTap.ShouldReceiveTouch = (recognizer, touch) =>
touch.View.Subviews.Any(sv =>
// Is this the NavigationBar's title or prompt?
(sv.Description.StartsWith("<UINavigationItemView") || sv.Description.StartsWith("<UINavBarPrompt")) &&
// Was the nested label actually tapped?
sv.Subviews.OfType<UILabel>().Any(label =>
label.Frame.Contains(touch.LocationInView(sv))));
NavigationController.NavigationBar.AddGestureRecognizer (navigationTitleTap);
Linq集合过滤器.OfType<T>
在查找视图层次结构中的特定类型时很方便。
这对我有用,这是基于Stavash的答案。我使用手势识别器的view属性在委托方法中返回YES/NO。
这是一个旧的应用,所以很明显这不是ARC,没有使用新的布局和nsattribuedstring。我留给你:p
- (void)viewDidLoad
{
...
CGRect r = self.navigationController.navigationBar.bounds;
UILabel *titleView = [[UILabel alloc] initWithFrame:r];
titleView.autoresizingMask =
UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
titleView.textAlignment = NSTextAlignmentCenter;
titleView.font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
titleView.text = self.title;
titleView.userInteractionEnabled = YES;
UITapGestureRecognizer *tgr =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(titleViewWasTapped:)];
tgr.numberOfTapsRequired = 1;
tgr.numberOfTouchesRequired = 1;
tgr.delegate = self;
[titleView addGestureRecognizer:tgr];
[tgr release];
self.navigationItem.titleView = titleView;
[titleView release];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
// This method is needed because the navigation bar with back
// buttons will swallow touch events
return (gestureRecognizer.view == self.navigationItem.titleView);
}
然后像往常一样使用手势识别器
- (void)titleViewWasTapped:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateRecognized) {
return;
}
...
}