【Swift UIKit】addTargetメソッドの使い方と意味!UIControlとEventの種類
この記事からわかること
- SwiftのUIKitでUIControlに処理を紐づける方法
- UIControlクラスとは?
- addTargetメソッドの使い方と実装方法
- UIControl.Eventで指定できる
イベント
一覧
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
SwiftのUIKitでボタンなどのUIコンポーネント使用時に登場するaddTarget
メソッドの使い方などを備忘録がてらまとめていきます。基本的には公式リファレンスの要約になっています。
UIControlクラス
@MainActor class UIControl : UIView
UIKitで使用するUIButton
やUITextField
などのコントロール群はユーザーの操作に対して特定のアクションを管理するためのUIControl
クラスを継承して定義されているクラスです。そのためこのクラスのインスタンスを生成して使用するわけではなく継承したUIButton
などにメソッドを提供する役割となっています。
UIControl
クラスにはコントロールが有効かどうかを識別するためのisEnabled
プロパティやアクションを追加するためのaddTarget
メソッドなど管理するために必要な機能や情報を保持しています。
@MainActor class UIControl : UIView {
var state: UIControl.State // コントロールの状態
var isEnabled: Bool // コントロールが有効な状態かどうかを示すブール値
var isSelected: Bool // コントロールが選択された状態にあるかどうかを示すブール値
var isHighlighted: Bool // コントロールがハイライトを描画するかどうかを示すブール値
var contentVerticalAlignment: UIControl.ContentVerticalAlignment // コンテンツの垂直方向の配置
var contentHorizontalAlignment: UIControl.ContentHorizontalAlignment // コンテンツの水平方向の配置
func addTarget(Any?, action: Selector, for: UIControl.Event) // イベントとアクションメソッドをコントロールに関連付ける
func removeTarget(Any?, action: Selector?, for: UIControl.Event) // イベントの配信を停止
func sendAction(Selector, to: Any?, for: UIEvent?) // イベントなしでアクションメソッドを呼び出す
.
.
}
addTargetメソッド
addTarget
メソッドはその名の通りコントロールに対してターゲットとなるオブジェクトと処理部分であるアクションを紐付けるためのメソッドです。
func addTarget(
_ target: Any?,
action: Selector,
for controlEvents: UIControl.Event
)
引数の意味
- target:アクションメソッドを呼び出すオブジェクトを指定
- action:呼び出されるアクションメソッドを識別するセレクターを指定
- for controlEvents:UIControl.Event形式のイベントを指定
使用例
class ViewController: UIViewController {
let button = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
let screenWidth = self.view.frame.width
let screenHeight = self.view.frame.height
button.frame = CGRect(x:screenWidth/4, y:screenHeight/2,
width:screenWidth/2, height:60)
button.setTitle("ボタン", for:UIControl.State.normal)
button.addTarget(self,
action: #selector(ViewController.buttonTapped),
for: .touchUpInside)
self.view.addSubview(button)
}
@objc func buttonTapped()) {
print("ボタンをタップされたよ")
}
}
target
_ target: Any?,
引数targetにはactionメソッドが呼び出されるオブジェクト(クラス)を指定します。上記の例の場合呼び出すアクションメソッドbuttonTapped
はViewController
クラスのメソッドとして定義しているのでself
と指定すればOKです。
定義しているクラスが違う場合はここにメソッドを定義しているクラスを明示的に指定します。Any?
型となっているので渡すデータ型に制限はなく、nil
も許容しているようです。
ターゲットにnil
を指定した場合はUIKitが対象のアクションメソッドを検索してくれるようです。なので上記の例をnil
に変更しても正常に動作しましたが、デメリットが何かあるのでしょうか?
action
action: Selector,
引数actionには呼び出されるactionメソッドを識別するセレクター(Selector)を指定します。
Selector構造体
引数に渡すSelector
構造体はSwiftではなくObjective-Cの仕様です。Swiftには現段階で存在しない仕様のためObjective-Cの概念がここで使用されているようです。
#selector
形式で引数に対象のメソッド名を渡すことでUIControlインスタンスとメソッドの紐付けが完了します。
#selector
で指定するメソッドには以下のように引数を持たせることができます。渡せるのは呼び出しているUIControlインスタンス
とUIEvent
です。
#selector(ViewController.buttonTapped)
#selector(ViewController.buttonTapped(sender:forEvent:)),
#selector(ViewController.buttonTapped(sender:forEvent:)),
@IBAction func buttonTapped()
@IBAction func buttonTapped(sender: UIButton)
@IBAction func buttonTapped(sender: UIButton, forEvent event: UIEvent)
引数の例
// タップされたときのaction
button.addTarget(nil,
action: #selector(ViewController.buttonTapped(sender:forEvent:)),
for: .touchUpInside)
}
@objc func buttonTapped(sender: UIButton, forEvent event: UIEvent){
print("ボタンをタップされたよ") // ボタンをタップされたよ
print(sender.titleLabel?.text) // Optional("ボタン")
print(event) // <UITouchesEvent: 0x600002688000> timestamp: 767332 touches: {( <UITouch: 0x14ad041f0> phase: Ended tap count: 1 force: 0.000 window: <UIWindow: 0x14960ceb0; frame = (0 0; 428 926); gestureRecognizers = <NSArray: 0x600001df2df0>; layer = <UIWindowLayer: 0x600001df2d90>> view: <UIButton: 0x14960b160; frame = (107 463; 214 60); opaque = NO; layer = <CALayer: 0x6000013d8b00>> location in window: {229.33332824707031, 513} previous location in window: {229.33332824707031, 513} location in view: {122.33332824707031, 50} previous location in view: {122.33332824707031, 50} )}
}
controlEvents
引数controlEventsにはトリガーとなるイベント条件を渡します。イベント条件はUIControl.Event
型として定義されている値を指定します。
UIControl.Event
UIControl.Event
型にはタップやドラッグなどのユーザー操作イベントが定義されています。
static var touchDown: UIControl.Event // コントロールでのタッチダウンイベント
static var touchDownRepeat: UIControl.Event // コントロール内で繰り返されるタッチダウンイベント。このイベントでは、UITouchメソッドのtapCount値が1より大きい
static var touchDragInside: UIControl.Event // コントロールの境界内で指がドラッグされるイベント
static var touchDragOutside: UIControl.Event // コントロールの境界のすぐ外側に指がドラッグされるイベント
static var touchDragEnter: UIControl.Event // 指がコントロールの境界内にドラッグされるイベント
static var touchDragExit: UIControl.Event // 指がコントロール内からその境界の外にドラッグされるイベント
static var touchUpInside: UIControl.Event // 指がコントロールの境界内にあるコントロールのタッチアップイベント
static var touchUpOutside: UIControl.Event // 指がコントロールの境界外にあるコントロール内のタッチアップイベント
static var touchCancel: UIControl.Event // コントロールの現在のタッチをキャンセルするシステムイベント
static var valueChanged: UIControl.Event // コントロールをタッチ、ドラッグまたはその他の方法で操作すると、一連の異なる値が出力
static var menuActionTriggered: UIControl.Event // メニューが表示される前に、メニューアクションがトリガー
static var primaryActionTriggered: UIControl.Event // ボタンによってトリガーされるセマンティックアクション
static var editingDidBegin: UIControl.Event // UITextFieldオブジェクトの境界に入って編集セッションを開始するタッチ
static var editingChanged: UIControl.Event // UITextFieldオブジェクトの編集を変更するタッチ
static var editingDidEnd: UIControl.Event // UITextFieldオブジェクトの境界を離れて編集セッションを終了するタッチ
static var editingDidEndOnExit: UIControl.Event // UITextFieldオブジェクトの編集セッションを終了するタッチ
static var allTouchEvents: UIControl.Event // すべてのタッチ イベント
static var allEditingEvents: UIControl.Event // UITextFieldオブジェクトのすべての編集タッチ
static var applicationReserved: UIControl.Event // アプリケーションで使用できる制御イベント値の範囲
static var systemReserved: UIControl.Event // 内部フレームワーク用に予約されている制御イベント値の範囲
static var allEvents: UIControl.Event // システムイベントを含むすべてのイベント
複数のaddTargetを登録する
1つのUIControl
インスタンスには複数のイベント処理を登録することも可能です。addTarget
メソッドは何度呼び出しても問題ないメソッドなので異なるイベント発生時にさまざまな処理を行わせることができます。
button.addTarget(nil,
action: #selector(ViewController.buttonTapped),
for: .touchUpInside)
button.addTarget(nil,
action: #selector(ViewController.buttonDrag),
for: .touchDragInside)
// Viewにボタンを追加
self.view.addSubview(button)
}
@objc func buttonTapped(){
print("ボタンをタップされたよ")
}
@objc func buttonDrag(){
print("ボタンをドラッグされたよ")
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。