【Swift】UIResponderとは?ビューのフォーカス管理と仕組み
この記事からわかること
- SwiftのUIResponderとは?
- フォーカス管理の仕組み
- Responder Chainとは?
- First Responderとは?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:16.0
- iOS:18.0
- Swift:5.9
- macOS:Sonoma 14.6.1
iOSのフォーカス管理の仕組み
iOSアプリでユーザーがビュー階層内のどのビューにフォーカスがあたりイベントが発生しているかをResponder Objectとして管理されています。フォーカスが当たっている状態とは入力欄などでキーボードが表示されている状態のことになります。
Responder Objectがタッチやジェスチャーなどのイベントをシステムから受け取り、処理できるイベントであれば処理します。処理できない場合はResponder Chainに従ってイベントを転送していきます。
Responder Chain
Responder Objectは「Responder Chain」と呼ばれる一連の流れと密に関係しています。Responder Chainはビューの親子関係や階層関係に基づいて構築されており、ユーザーが画面をタップした際にイベントが発生するとそのイベントを処理できるResponder ObjectをResponder Chainを辿って探します。
First Responder
Responder Chainを辿って最初に見つかったイベントを処理できるResponder Objectを「First Responder」と呼びます。
UIResponderクラス
@MainActor
class UIResponder : NSObject
Responder ObjectはUIResponder
クラスとして定義されています。このクラスがiOSアプリでイベント(タッチ、モーション、リモートコントロール、キーボード入力など)を処理するための基底クラスになり、イベントを処理するためのメソッドを定義しています。
UIResponder
はUIView
、UIViewController
、UIApplication
の親クラスになっており実際に意識することは少ない印象です。ここではイベント処理の仕組みがビューやビューコントローラーも継承していることが大事になります。
タッチイベントメソッド
UIResponder
はイベントを処理するためのメソッドが複数定義されています。
- touchesBegan(_:with:):ユーザーがタッチした時に呼ばれる
- touchesMoved(_:with:):ユーザーがタッチを移動した時に呼ばれる
- touchesEnded(_:with:):ユーザーがタッチを離した時に呼ばれる
- touchesCancelled(_:with:):システムイベントなどによりタッチがキャンセルされた時に呼ばれる
First Responderの管理
UIResponder
はFirst Responderを管理するためのプロパティやメソッドが複数定義されています。
- isFirstResponder:このオブジェクトがFirst Responderかどうか
- canBecomeFirstResponder:このオブジェクトがFirst Responderになれるかどうか
- becomeFirstResponder():First Responderになるように要求する
- resignFirstResponder():First Responderを辞任する
例えばUITextField
やUITextView
などの入力UI部品はフォーカスがあたりFirst Responderになるとキーボードが表示されます。resignFirstResponder
メソッドを呼び出してFirst Responderを辞任することでキーボードを閉じることができるようになります。
FirstResponder(フォーカスの当たっている)のViewを取得する
現在FirstResponder(フォーカスの当たっている)Viewを取得するための拡張プロパティを実装してみました。
extension UIView {
/// フォーカスの当たっているViewを取得する
var currentFirstResponder: UIView? {
if self.isFirstResponder {
return self
}
for subview in self.subviews {
if let responder = subview.currentFirstResponder {
return responder
}
}
return nil
}
}
例えばViewController内でこのプロパティからFirstResponderになっているViewを取得することができます。
// 例:FirstResponderなのがUITextFieldの場合に取得する
guard let activeField = self.view.currentFirstResponder as? UITextField else { return }
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。