UIKit — UIResponder

以下是关于 UIResponder 体系结构的详细分类介绍,并按照表格形式整理。


UIResponder 体系结构概述 #

UIResponder 是 iOS 开发中的一个核心协议,定义了事件处理的基本机制。它是 UIKit 中所有能够响应用户交互的对象(如 UIViewControllerUIViewUIApplication)的基类或协议。通过 UIResponder,可以实现触摸事件、键盘事件以及其他系统事件的分发和处理。


UIResponder 的主要功能与方法 #

1. 事件处理链 #

UIResponder 定义了一个事件响应链(Responder Chain),用于将事件从第一响应者传递到其父级响应者,直到事件被处理或到达链的终点。

2. 主要方法分类 #

以下是 UIResponder 的主要方法分类及功能: 以下是 UIResponder 的完整功能分类表格,按模块和功能层级整理所有属性和方法:


UIResponder 功能分类总表 #

分类属性/方法描述典型应用场景
响应链管理var next: UIResponder?指向响应链中的下一个响应者手动传递事件到下一个响应者(如自定义事件处理)
var isFirstResponder: Bool当前对象是否为第一响应者检查焦点状态(如判断键盘是否显示)
var canBecomeFirstResponder: Bool是否允许成为第一响应者控制自定义控件能否获取焦点(如自定义输入视图)
func becomeFirstResponder() -> Bool尝试成为第一响应者主动触发键盘弹出或输入焦点
var canResignFirstResponder: Bool是否允许放弃第一响应者状态控制是否允许隐藏键盘
func resignFirstResponder() -> Bool放弃第一响应者状态主动隐藏键盘或结束编辑
触摸事件响应func touchesBegan(Set<UITouch>, with: UIEvent?)触摸开始事件自定义手势识别(如绘图起点)
func touchesMoved(Set<UITouch>, with: UIEvent?)触摸移动事件跟踪拖动操作(如移动视图)
func touchesEnded(Set<UITouch>, with: UIEvent?)触摸结束事件完成触摸操作(如释放按钮)
func touchesCancelled(Set<UITouch>, with: UIEvent?)触摸被系统取消事件清理未完成的触摸状态(如来电打断)
func touchesEstimatedPropertiesUpdated(Set<UITouch>)更新预估触摸属性(如压感)处理 Apple Pencil 压感数据
运动事件响应func motionBegan(UIEvent.EventSubtype, with: UIEvent?)设备运动开始(如摇动)实现“摇一摇”功能
func motionEnded(UIEvent.EventSubtype, with: UIEvent?)设备运动结束响应摇动操作后的逻辑
func motionCancelled(UIEvent.EventSubtype, with: UIEvent?)运动事件被取消清理运动事件状态
按压事件响应func pressesBegan(Set<UIPress>, with: UIPressesEvent?)物理按钮按下事件(如游戏控制器)游戏中的按键操作处理
func pressesChanged(Set<UIPress>, with: UIPressesEvent?)按压状态变化事件处理按钮压力值变化(如游戏扳机键)
func pressesEnded(Set<UIPress>, with: UIPressesEvent?)物理按钮释放事件结束按键操作
func pressesCancelled(Set<UIPress>, with: UIPressesEvent?)按压事件被取消清理按键操作状态
远程控制事件func remoteControlReceived(with: UIEvent?)响应远程控制事件(如耳机按钮)音乐播放器的播放/暂停控制
输入视图管理var inputView: UIView?自定义输入视图(如自定义键盘)替换系统键盘为自定义输入界面
var inputViewController: UIInputViewController?自定义输入视图控制器管理复杂的输入视图逻辑
var inputAccessoryView: UIView?输入辅助视图(如键盘顶部工具栏)添加快捷操作按钮(如“完成”按钮)
var inputAccessoryViewController: UIInputViewController?输入辅助视图控制器管理辅助视图的交互逻辑
func reloadInputViews()刷新输入视图动态切换输入视图(如切换键盘类型)
撤销管理器var undoManager: UndoManager?获取响应链中的撤销管理器实现文本编辑的撤销/重做功能
菜单与命令处理func buildMenu(with: any UIMenuBuilder)动态构建上下文菜单自定义长按菜单选项
func validate(UICommand)验证菜单命令是否可用根据上下文启用/禁用菜单项
func canPerformAction(Selector, withSender: Any?) -> Bool判断是否支持某个动作控制剪切/复制/粘贴的可用性
func target(forAction: Selector, withSender: Any?) -> Any?查找响应动作的目标对象自定义事件传递逻辑
键盘命令var keyCommands: [UIKeyCommand]?定义物理键盘快捷键支持外接键盘操作(如 Cmd+S 保存)
文本输入模式var textInputMode: UITextInputMode?当前文本输入模式(如语言、键盘类型)动态切换输入法
var textInputContextIdentifier: String?标识符用于保存输入模式配置恢复用户上次使用的输入法
class func clearTextInputContextIdentifier(String)清除保存的输入模式配置重置输入法状态
var inputAssistantItem: UITextInputAssistantItem键盘辅助工具栏配置自定义快捷输入栏(如常用符号)
用户活动管理var userActivity: NSUserActivity?关联的用户活动(用于 Handoff 或 Siri 快捷指令)实现跨设备任务接续
func restoreUserActivityState(NSUserActivity)恢复用户活动状态从其他设备继续未完成任务
func updateUserActivityState(NSUserActivity)更新用户活动状态同步当前任务进度
活动项配置var activityItemsConfiguration: (any UIActivityItemsConfigurationReading)?定义分享内容(如文本、图片)自定义分享菜单的内容
编辑交互配置var editingInteractionConfiguration: UIEditingInteractionConfiguration配置编辑交互行为(如文本选择、放大镜)控制文本选择的交互方式
相机文本捕捉func captureTextFromCamera(Any?)启动相机扫描文本快速输入相机捕捉的文字(iOS 15+)
Touch Bar 管理func makeTouchBar() -> NSTouchBar?创建自定义 Touch Bar(仅 macOS)为 macOS 应用添加 Touch Bar 控件
var touchBar: NSTouchBar?当前 Touch Bar 对象动态更新 Touch Bar 内容
键盘通知常量keyboardAnimationCurveUserInfoKey键盘动画曲线(从通知的 userInfo 中获取)同步视图与键盘动画
keyboardAnimationDurationUserInfoKey键盘动画时长(单位:秒)调整布局动画时间
keyboardDidChangeFrameNotification键盘 frame 变化后的通知监听键盘位置变化
keyboardFrameEndUserInfoKey键盘动画结束时的 frame计算布局避免遮挡
keyboardWillShowNotification键盘即将显示的通知提前调整界面布局

UIResponder 的继承关系与实现 #

1. 继承关系 #

UIResponder 是以下类的基类或协议:

  • UIApplication
  • UIWindow
  • UIViewController
  • UIView
  • UIDynamicAnimator
  • UIPreviewInteraction

这些类共同构成了 iOS 应用的事件响应体系。

分类子类/相关类功能描述典型应用场景
核心视图组件UIView所有视图的基类,处理触摸、按压等事件自定义视图、布局控件
UIControl交互控件基类(如按钮、滑块),提供 target-action 机制按钮点击 (UIButton)、滑块拖动 (UISlider)
控制器相关UIViewController视图控制器的基类,管理视图生命周期和事件传递页面跳转、数据传递
UINavigationController导航控制器,管理视图控制器的堆栈实现层级页面导航
UITabBarController标签栏控制器,管理多个并列视图控制器底部 Tab 切换
应用与窗口UIApplication应用单例对象,管理全局事件(如远程控制、推送)处理应用级事件(如远程播放控制)
UIWindow应用的窗口容器,根视图的承载者设置根视图控制器、处理窗口级事件
文本输入处理UITextField单行文本输入控件,支持键盘交互登录表单、搜索框
UITextView多行文本输入控件,支持富文本编辑长文本编辑、聊天输入框
手势与交互扩展UIGestureRecognizer手势识别器基类(非直接子类,但依赖 UIResponder 方法)识别点击、滑动、捏合等手势
UIScrollView滚动视图,处理滑动事件和缩放列表滚动、图片缩放
系统事件扩展UIKeyCommand响应物理键盘事件(需在 UIResponder 子类中实现 keyCommands 属性)支持 Mac Catalyst 或外接键盘的快捷键
UIPress响应物理按钮按压事件(如游戏控制器)游戏开发中的手柄输入
自定义响应者自定义 UIResponder 子类实现自定义事件处理逻辑(需重写 touchesBeganmotionEnded 等方法)处理特殊硬件输入(如蓝牙设备)

2. 实现方式 #

  • 第一响应者:只有成为第一响应者(First Responder)的对象才能直接接收用户输入事件。
  • 事件分发:如果当前对象无法处理某个事件,则会将其传递给下一个响应者(通常是其父视图控制器或窗口)。
  • 自定义处理:开发者可以通过重写上述方法来自定义事件处理逻辑。

事件传递与响应链(Responder Chain) #

层级对象示例传递顺序
第一响应者UITextField(当前焦点)事件首先传递给第一响应者,若未处理则向上传递
视图层级UIViewSuperview → …从子视图向父视图逐级传递
视图控制器UIViewController若视图未处理事件,传递给其所属的视图控制器
窗口与应用UIWindowUIApplication最终传递至窗口和应用对象

典型代码示例 #

1. 自定义手势处理(重写 touchesMoved #

class CustomView: UIView {
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let location = touch.location(in: self)
        print("Touch moved to: \(location)")
    }
}

2. 监听物理键盘事件(UIKeyCommand #

class MyViewController: UIViewController {
    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(input: "S", modifierFlags: .command, action: #selector(saveDocument))
        ]
    }
    
    @objc func saveDocument() {
        print("Cmd+S pressed")
    }
}

3. 控制第一响应者状态 #

class EditableLabel: UIView {
    override var canBecomeFirstResponder: Bool { true }
    
    override func becomeFirstResponder() -> Bool {
        let result = super.becomeFirstResponder()
        if result { self.backgroundColor = .highlightedColor }
        return result
    }
}

¥### 4:处理摇晃事件

override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
    if motion == .motionShake {
        print("设备被摇晃")
    }
}

代码示例补充 #

1. 自定义输入视图 #

class CustomInputView: UIView { /* 实现自定义键盘 */ }

class MyTextField: UITextField {
    override var inputView: UIView? {
        return CustomInputView()
    }
}

2. 监听键盘通知 #

NotificationCenter.default.addObserver(
    self,
    selector: #selector(keyboardWillShow(_:)),
    name: UIResponder.keyboardWillShowNotification,
    object: nil
)

@objc func keyboardWillShow(_ notification: Notification) {
    guard let frame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
    print("Keyboard height: \(frame.height)")
}

3. 添加快捷键支持 #

class EditorViewController: UIViewController {
    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(input: "s", modifierFlags: .command, action: #selector(saveDocument))
        ]
    }
    
    @objc func saveDocument() {
        // 保存操作
    }
}

高级应用场景 #

  1. 跨响应者通信
    通过 next 属性手动传递事件:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if !handleEventLocally() {
            next?.touchesBegan(touches, with: event)
        }
    }
    
  2. 结合 Combine 监听响应者链变化
    使用 NotificationCenter 监听 UITextField 焦点变化:

    .onReceive(NotificationCenter.default.publisher(for: UITextField.textDidBeginEditingNotification)) { notification in
        guard let textField = notification.object as? UITextField else { return }
        print("Focus on: \(textField)")
    }
    
  3. 自定义远程控制事件
    处理耳机按钮或外部设备事件:

    override func remoteControlReceived(with event: UIEvent?) {
        guard let event = event else { return }
        switch event.subtype {
        case .remoteControlPlay: player.play()
        case .remoteControlPause: player.pause()
        default: break
        }
    }
    

总结要点 #

  • 核心角色:UIResponder 是 UIKit 事件处理的基础,贯穿整个响应链。
  • 灵活扩展:通过子类化和重写方法,可定制复杂交互逻辑(如游戏控制器、绘图工具)。
  • 系统集成:与手势识别器、文本输入、物理键盘等深度结合,覆盖全平台交互场景。
  • 性能优化:避免在频繁触发的触摸方法中执行耗时操作,需结合 RunLoop 或异步处理。

注意事项 #

  1. 优先级:某些事件(如触摸事件)优先级较高,可能会覆盖其他事件的处理。
  2. 性能优化:避免在事件处理方法中执行耗时操作,以免影响用户体验。
  3. 调试工具:可以使用 Xcode 的调试工具查看事件响应链的具体路径。
本文共 3192 字,创建于 Feb 23, 2025
相关标签: Xcode, UIKit