UIButton可见但无法响应点击,求排查子视图添加问题
问题现象
UIButton能正常显示,但点击时既无动画/高亮反馈,绑定的buttonTapped:方法也完全不响应,怀疑是子视图添加逻辑导致的问题。
视图层级结构
BoardView → EvilEndgame实例 → QuickMove实例(按钮所在容器)
EvilEndgame 初始化代码
// EvilEndgame.m -(void) initializeChessBoard: (UIView*) boardView boardDict: (NSMutableDictionary*) board { // Properties self.engine = [[NSMutableDictionary alloc] init]; // ScoresLayer self.scoresLayer = [ScoresLayer sharedInstance]; self.scoresLayer.boardView = boardView; self.scoresLayer.board = board; // QuickMove self.quickMove = [QuickMove sharedInstance]; [self.quickMove startNewGame]; [boardView addSubview: self.quickMove]; self.quickMove.delegate = self; }
QuickMove 核心代码
// QuickMove.m + (instancetype)sharedInstance { static QuickMove *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[QuickMove alloc] init]; // Set the bounds to match the screen bounds sharedInstance.bounds = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height); // Set the center to adjust the position sharedInstance.center = CGPointMake([UIScreen mainScreen].bounds.size.width / 2, 415 + [UIScreen mainScreen].bounds.size.height / 2); }); return sharedInstance; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor grayColor]; } return self; } - (void)startNewGame { for (UIButton *button in self.buttons) { [button removeFromSuperview]; } for (UIButton *button in self.smartMoveButtons) { [button removeFromSuperview]; } [self.buttons removeAllObjects]; [self.smartMoveButtons removeAllObjects]; [self createButtons]; } - (void)createButtons { self.buttons = [[NSMutableArray alloc] init]; self.smartMoveButtons = [[NSMutableArray alloc] init]; CGFloat buttonWidth = self.bounds.size.width / 8; // 8 original buttons CGFloat buttonHeight = 50; CGFloat smartMoveWidth = 50; // 3 smartMove buttons // Create smartMove buttons with spacing CGFloat spacing = 1; int tag = 100; // Start smart button tags from 100 for (int i = 1; i <= 3; i++) { CGFloat offset = (i - 1) * (smartMoveWidth + spacing); UIButton *smartMoveButton = [self createButtonWithTitle:[NSString stringWithFormat:@"SM%d", i] frame:CGRectMake(offset, 0, smartMoveWidth, buttonHeight) tag:tag++]; [self.smartMoveButtons addObject:smartMoveButton]; } // Create original buttons with spacing tag = 0; // Start original button tags from 0 for (int i = 1; i <= 8; i++) { CGFloat offset = (i - 1) * (buttonWidth + spacing); UIButton *originalButton = [self createButtonWithTitle:[NSString stringWithFormat:@"B%d", i] frame:CGRectMake(offset, buttonHeight, buttonWidth, buttonHeight) tag:tag++]; [self.buttons addObject:originalButton]; } } - (UIButton *)createButtonWithTitle:(NSString *)title frame:(CGRect)frame tag:(NSInteger)tag { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = frame; [button setTitle:title forState:UIControlStateNormal]; [self configureButton:button]; [button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchDown]; // Assign tag to button button.tag = tag; [self addSubview:button]; return button; } - (void)configureButton:(UIButton *)button { button.titleLabel.font = [UIFont systemFontOfSize:13]; button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; button.titleLabel.numberOfLines = 4; // Fixes label position button.contentVerticalAlignment = UIControlContentVerticalAlignmentTop; button.backgroundColor = self.backgroundColor; }
旧版本有效实现(当前已失效)
之前项目中直接将按钮添加到根控制器视图的方式,现在会导致按钮完全不显示,推测是相关API已被弃用:
UIViewController *rootViewController = (UIViewController*)[[[UIApplication sharedApplication] keyWindow] rootViewController]; // 在QuickMove里直接把按钮加到根控制器视图上 [rootViewController.view addSubview:button];
问题根源与解决步骤
1. QuickMove的frame/bounds设置错误
在sharedInstance初始化逻辑中,仅设置bounds和center但未正确设置frame,而默认init调用的是initWithFrame:CGRectZero,导致QuickMove的响应区域可能超出父视图boardView范围,或尺寸无效。iOS中视图的点击响应由frame决定,父视图响应区域异常会导致子视图按钮无法接收点击事件。
修复代码:
+ (instancetype)sharedInstance { static QuickMove *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ CGRect screenBounds = [UIScreen mainScreen].bounds; // 直接设置frame,确保位置和尺寸适配父视图 sharedInstance = [[QuickMove alloc] initWithFrame:CGRectMake(0, 415, screenBounds.size.width, screenBounds.size.height)]; }); return sharedInstance; }
2. 检查userInteractionEnabled属性
确保以下视图的userInteractionEnabled均为YES:
QuickMove本身(默认YES,但需确认未被意外修改)- 所有按钮(默认YES)
- 父视图
EvilEndgame和BoardView
补充代码(可加在QuickMove的initWithFrame:中):
self.userInteractionEnabled = YES;
3. 修正按钮绑定的控制事件
当前绑定的UIControlEventTouchDown仅触发手指按下瞬间的事件,无法提供标准点击反馈,建议改为按钮点击的标准事件UIControlEventTouchUpInside。
修复代码:
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
4. 排查视图层级遮挡
使用Xcode的Debug View Hierarchy工具检查视图层级,确认QuickMove及按钮未被其他视图(如scoresLayer)遮挡,确保按钮处于可交互的最上层。
内容的提问来源于stack exchange,提问作者BBedit
相关产品推荐
相关产品推荐

