【Swift UIKit】addTargetメソッドの使い方と意味!UIControlとEventの種類

この記事からわかること

  • SwiftUIKitUIControl処理紐づける方法
  • UIControlクラスとは?
  • addTargetメソッド使い方実装方法
  • UIControl.Eventで指定できるイベント一覧

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

SwiftのUIKitでボタンなどのUIコンポーネント使用時に登場するaddTargetメソッドの使い方などを備忘録がてらまとめていきます。基本的には公式リファレンスの要約になっています。

UIControlクラス

公式リファレンス:UIControl

@MainActor  class UIControl : UIView

UIKitで使用するUIButtonUITextFieldなどのコントロール群はユーザーの操作に対して特定のアクションを管理するための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メソッド

addTargetメソッドはその名の通りコントロールに対してターゲットとなるオブジェクトと処理部分であるアクションを紐付けるためのメソッドです。

func addTarget(
    _ target: Any?,
    action: Selector,
    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メソッドが呼び出されるオブジェクト(クラス)を指定します。上記の例の場合呼び出すアクションメソッドbuttonTappedViewControllerクラスのメソッドとして定義しているのでselfと指定すればOKです。

定義しているクラスが違う場合はここにメソッドを定義しているクラスを明示的に指定します。Any?型となっているので渡すデータ型に制限はなく、nilも許容しているようです。

ターゲットにnilを指定した場合はUIKitが対象のアクションメソッドを検索してくれるようです。なので上記の例をnilに変更しても正常に動作しましたが、デメリットが何かあるのでしょうか?

action

action: Selector,

引数actionには呼び出されるactionメソッドを識別するセレクター(Selector)を指定します。

Selector構造体

引数に渡すSelector構造体はSwiftではなくObjective-Cの仕様です。Swiftには現段階で存在しない仕様のためObjective-Cの概念がここで使用されているようです。

#selector形式で引数に対象のメソッド名を渡すことでUIControlインスタンスとメソッドの紐付けが完了します。

Objective-C:Selector

#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("ボタンをドラッグされたよ")
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index