iOS 11(Swift 4、Xcode 9.X)中First Responder缺失问题求助
搞定第一响应者检测的问题
兄弟,我之前也踩过类似的第一响应者检测坑,结合你说的无Storyboard精简App的情况,咱们一步步来排查解决:
1. 先搞懂核心:普通UIView默认不能当第一响应者
这大概率是你检测全返回false的原因——系统默认的UIView是没有成为第一响应者的权限的,得咱们手动开权限。
给你的topView(或者你想设为第一响应者的视图)重写canBecomeFirstResponder方法,返回true:
class TopView: UIView { // 允许这个视图成为第一响应者 override var canBecomeFirstResponder: Bool { return true } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) // 现在再检测试试 checkFirstResponderStatus() } private func checkFirstResponderStatus() { print("TopView 是否是第一响应者?\(isFirstResponder)") print("主视图 是否是第一响应者?\(superview?.isFirstResponder ?? false)") print("窗口 是否是第一响应者?\(UIApplication.shared.keyWindow?.isFirstResponder ?? false)") } }
2. 主动让视图“上位”成第一响应者
光开权限还不够,得在合适的时机让它主动成为第一响应者,比如视图加载完成后:
class ViewController: UIViewController { var topView: TopView! override func viewDidLoad() { super.viewDidLoad() setupTopView() // 用异步确保视图已经完成布局,再调用成为第一响应者的方法 DispatchQueue.main.async { self.topView.becomeFirstResponder() } } private func setupTopView() { topView = TopView(frame: CGRect(x: 0, y: 100, width: view.frame.width, height: 100)) topView.backgroundColor = .orange view.addSubview(topView) } }
3. 换个姿势获取触摸对应的响应者
如果还是有问题,你可以直接从触摸事件里拿到触发触摸的视图,看看它的第一响应者状态:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) guard let touch = touches.first, let touchedView = touch.view else { return } print("当前触摸的视图:\(touchedView)") print("这个视图是第一响应者吗?\(touchedView.isFirstResponder)") }
4. 排查响应链的特殊情况
你说这不是简单的视图层级,那得留意有没有自定义容器视图(比如UIScrollView子类、自定义导航容器)干扰了响应链。可以给UIResponder加个扩展,跟踪第一响应者的变化日志:
extension UIResponder { override open func becomeFirstResponder() -> Bool { print("\(self) 成为了第一响应者") return super.becomeFirstResponder() } override open func resignFirstResponder() -> Bool { print("\(self) 退出了第一响应者") return super.resignFirstResponder() } }
这样你就能清晰看到哪个对象在什么时候切换第一响应者状态,快速定位问题出在哪。
内容的提问来源于stack exchange,提问作者eharo2
相关产品推荐
相关产品推荐

