You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为UIBarButtonItem两侧添加UITapGestureRecognizer扩大点击区域

结论

该需求完全可以实现,有两种可行方案,根据你的实际场景选择即可。

方案1:直接扩大按钮热区(优先推荐,无需手势)

这是实现成本最低、无冲突的方案,不需要依赖你加在导航栏上的手势识别器:

  • 直接把自定义UIButton的尺寸拓宽,覆盖左右各25像素的响应范围
  • 通过imageEdgeInsets调整图标显示位置,保持视觉效果和你原来的设计完全一致
  • 系统会自动将按钮的bounds作为点击响应区域,不需要额外写点击判断逻辑

对应修改后的createSearchButton代码:

- (UIButton *) createSearchButton {
    UIButton *searchButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [searchButton setImage:[UIImage sdk_imageName:@"Search_header_black"]
                 forState:UIControlStateNormal];
    
    [searchButton addTarget:self action:@selector(searchBarButtonClick) forControlEvents:UIControlEventTouchUpInside];
    // 原宽度32,左右各扩展25像素,总宽度为32 + 25*2 = 82
    searchButton.size = CGSizeMake(82, 30);
    // 调整图标偏移量,保持视觉位置和原设计一致(原left偏移8,加上左侧扩展的25,总偏移33)
    searchButton.imageEdgeInsets = UIEdgeInsetsMake(0, 33, 0, 0);
    return searchButton;
}
方案2:通过现有导航栏手势识别器判断点击位置

如果你有特殊需求必须用手势实现(比如扩展区域的点击要执行和按钮点击不同的逻辑),可以在手势回调中判断点击坐标是否落在目标范围内,步骤如下:

  1. 将searchButton设置为类的持有属性,不要仅作为局部变量使用,方便后续获取位置
  2. 给手势设置cancelsTouchesInView = NO,避免手势拦截导航栏上其他控件(如返回按钮、其他barButtonItem)的原生点击事件
  3. 在手势回调中,将点击坐标和按钮位置都转换到导航栏的坐标系下,判断点击是否落在按钮左右各25像素的扩展范围内

对应代码实现:

// 首先在类的延展中添加属性,持有搜索按钮
@property (nonatomic, strong) UIButton *searchButton;

// 初始化导航栏相关控件的部分代码
self.searchButton = [self createSearchButton];
UIBarButtonItem *searchBarItem = [[UIBarButtonItem alloc] initWithCustomView:self.searchButton];
// 按你的业务需求设置为left/rightBarButtonItem
self.navigationItem.leftBarButtonItem = searchBarItem;

UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleGestureForTopLeftNotificationBarButtonItem:)];
// 不拦截导航栏上其他控件的触摸事件
gr.cancelsTouchesInView = NO;
[self.navigationController.navigationBar addGestureRecognizer:gr];
// 手势回调实现
- (void)handleGestureForTopLeftNotificationBarButtonItem:(UITapGestureRecognizer *)gr {
    if (gr.state != UIGestureRecognizerStateRecognized) {
        return;
    }
    // 获取手势在导航栏上的点击坐标
    CGPoint tapLocation = [gr locationInView:self.navigationController.navigationBar];
    // 将搜索按钮的bounds转换为导航栏坐标系下的frame
    CGRect btnOriginalFrame = [self.searchButton convertRect:self.searchButton.bounds toView:self.navigationController.navigationBar];
    // 生成左右各扩展25像素的热区
    CGRect expandHotArea = CGRectInset(btnOriginalFrame, -25, 0);
    // 判断点击是否在扩展热区内,且不在按钮原有响应区域内(避免和按钮本身的点击事件重复触发)
    if (CGRectContainsPoint(expandHotArea, tapLocation) && !CGRectContainsPoint(btnOriginalFrame, tapLocation)) {
        // 执行对应逻辑
        [self searchBarButtonClick];
    }
}
注意事项
  • 坐标转换步骤不能省略:因为搜索按钮是作为UIBarButtonItem的customView存在的,它的默认父视图不是navigationBar,直接取frame会出现坐标偏移,导致热区判断错误
  • 如果使用手势方案,一定要设置cancelsTouchesInView = NO,否则会导致导航栏上其他系统或自定义按钮无法响应点击

内容的提问来源于stack exchange,提问作者stefanosn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 00:24:26