🈲

UIKitでButtonを作るにはどんな知識がいる?

2024/03/10に公開

読んでほしい人

  • iOS開発に興味がある
  • UIKitに興味がある

補足情報

私は昔はStoryboardでUI作ったり、SwiftUIでUzIを作る人なので、UIKitについては調べながら書いているので、間違っているところもあると思います。

今回は、Buttonを作るのにどれぐらいのコードや知識が必要なのかを言語化したいと思って記事にすることにしました。

Appleの公式ドキュメントは、UIButtonの作成と使用に関する詳細な情報を提供しています。以下にそのリンクと、ボタンの作成に関する基本的なコードを示します。

https://developer.apple.com/documentation/uikit/uibutton

UIKitで開発する環境を整えるにはこちらの記事を参考にしてください。

記事の内容

UIKitでボタンを作成するためには、以下のような基本的な知識が必要です:

UIButtonクラスの理解:UIButtonクラスは、ユーザーがタップするとアクションをトリガーする基本的なUI要素です。
ターゲット-アクションパターンの理解:ボタンがタップされたときに何をするかを定義するためには、ターゲット-アクションパターンを理解する必要があります。
Auto Layoutの理解:ボタンの位置とサイズを決定するためには、Auto Layoutというレイアウトシステムを理解する必要があります。
以下に、"保存"ボタンを作成するためのコードを示します:

// UIButtonのインスタンスを作成します。
let saveButton = UIButton(type: .system)

// ボタンのタイトルを設定します。第二引数のforは、ボタンの状態を指定します。
// .normalは、ボタンが通常状態(選択されていない、ハイライトされていない)のときを指します。
saveButton.setTitle("保存", for: .normal)

// ボタンがタップされたときに呼び出されるメソッドを設定します。
// #selectorは、呼び出すメソッドを指定します。ここではsaveButtonTappedというメソッドを指定しています。
// forは、イベントを指定します。.touchUpInsideは、ボタンの内部でタップが終了したときを指します。
saveButton.addTarget(self, action: #selector(saveButtonTapped), for: .touchUpInside)

// Auto Layoutを使用してボタンの位置とサイズを設定します。
saveButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    saveButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    saveButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    saveButton.widthAnchor.constraint(equalToConstant: 100),
    saveButton.heightAnchor.constraint(equalToConstant: 50),
])

// saveButtonTappedメソッドを定義します。このメソッドは、ボタンがタップされたときに呼び出されます。
@objc func saveButtonTapped() {
    // ここに保存ボタンがタップされたときの処理を書きます。
}

入力フォームを作るとしたらこれだけコード書くらしい...

import UIKit

class SecondScreen: UIViewController {
    
    let nameTextField: UITextField = {
        let textField = UITextField()
        textField.placeholder = "名前を入力"
        textField.borderStyle = .roundedRect
        textField.translatesAutoresizingMaskIntoConstraints = false
        return textField
    }()
    
    let genderSegmentedControl: UISegmentedControl = {
        let items = ["男性", "女性"]
        let segmentedControl = UISegmentedControl(items: items)
        segmentedControl.translatesAutoresizingMaskIntoConstraints = false
        return segmentedControl
    }()
    
    let ageTextField: UITextField = {
        let textField = UITextField()
        textField.placeholder = "年齢を入力"
        textField.borderStyle = .roundedRect
        textField.keyboardType = .numberPad
        textField.translatesAutoresizingMaskIntoConstraints = false
        return textField
    }()
    
    let submitButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("送信", for: .normal)
        button.backgroundColor = .black
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 10
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemMint
        
        setupViews()
        setupKeyboardDismissButton()
    }
    
    func setupViews() {
        view.addSubview(nameTextField)
        view.addSubview(genderSegmentedControl)
        view.addSubview(ageTextField)
        view.addSubview(submitButton)
        
        // AutoLayout constraints
        // Please adjust these according to your needs
        NSLayoutConstraint.activate([
            nameTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            nameTextField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
            nameTextField.widthAnchor.constraint(equalToConstant: 300),
            nameTextField.heightAnchor.constraint(equalToConstant: 50),
            
            genderSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            genderSegmentedControl.topAnchor.constraint(equalTo: nameTextField.bottomAnchor, constant: 20),
            
            ageTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            ageTextField.topAnchor.constraint(equalTo: genderSegmentedControl.bottomAnchor, constant: 20),
            ageTextField.widthAnchor.constraint(equalToConstant: 300),
            ageTextField.heightAnchor.constraint(equalToConstant: 50),
            
            submitButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            submitButton.topAnchor.constraint(equalTo: ageTextField.bottomAnchor, constant: 20),
            submitButton.widthAnchor.constraint(equalToConstant: 300),
            submitButton.heightAnchor.constraint(equalToConstant: 50),
        ])
    }
    
    func setupKeyboardDismissButton() {
        let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 50))
        toolbar.items = [
            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
            UIBarButtonItem(title: "閉じる", style: .done, target: self, action: #selector(dismissKeyboard))
        ]
        nameTextField.inputAccessoryView = toolbar
        ageTextField.inputAccessoryView = toolbar
    }
    
    @objc func dismissKeyboard() {
        view.endEditing(true)
    }
}

buildするとこんな感じ


簡単なカウンターアプリだとどれぐらいのコードを書くのか...

import UIKit

class SecondScreen: UIViewController {
    
    // ラベルとボタンを作成します。
    let label = UILabel()
    let minusButton = UIButton(type: .system)
    let plusButton = UIButton(type: .system)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 背景色がlight modeならwhite、dark modeならblackにする。
        view.backgroundColor = .systemBackground

        // ラベルの設定
        label.text = "0"
        label.font = UIFont.systemFont(ofSize: 30)
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        
        // ボタンのフォントのサイズを設定
        let attributes: [NSAttributedString.Key: Any] = [
            .font: UIFont.systemFont(ofSize: 30)
        ]
        
        // マイナスボタンの設定
        let minusAttributedTitle = NSAttributedString(string: "-", attributes: attributes)
        minusButton.setAttributedTitle(minusAttributedTitle, for: .normal)
        minusButton.addTarget(self, action: #selector(minusButtonTapped), for: .touchUpInside)
        minusButton.translatesAutoresizingMaskIntoConstraints = false
        
        // プラスボタンの設定
        let plusAttributedTitle = NSAttributedString(string: "+", attributes: attributes)
        plusButton.setAttributedTitle(plusAttributedTitle, for: .normal)
        plusButton.addTarget(self, action: #selector(plusButtonTapped), for: .touchUpInside)
        plusButton.translatesAutoresizingMaskIntoConstraints = false
        
        // ビューにラベルとボタンを追加
        view.addSubview(label)
        view.addSubview(minusButton)
        view.addSubview(plusButton)
        
        // Auto Layoutの制約を設定
        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            
            minusButton.centerYAnchor.constraint(equalTo: label.bottomAnchor, constant: 20),
            minusButton.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant: -10),
            
            plusButton.centerYAnchor.constraint(equalTo: label.bottomAnchor, constant: 20),
            plusButton.leadingAnchor.constraint(equalTo: view.centerXAnchor, constant: 10),
        ])
    }
    // マイナスのロジック
    @objc func minusButtonTapped() {
        // ラベルのテキストを整数として取得します。
        var value = Int(label.text!) ?? 0
        // 値を1減らします。
        value -= 1
        // ラベルのテキストを更新します。
        label.text = String(value)
    }
    // プラスのロジック
    @objc func plusButtonTapped() {
        // ラベルのテキストを整数として取得します。
        var value = Int(label.text!) ?? 0
        // 値を1増やします。
        value += 1
        // ラベルのテキストを更新します。
        label.text = String(value)
    }
}

長い長い...SwiftUIが簡単に感じる笑

最後に

今回は、UIKitを使ってボタンを作ってみました。いや〜ボタン作るだけでも長いコード書くんですね😅
UIKitの知識が必要だから勉強してますが、難しいな〜
宣言的UIが流行るのは、短いコードでイメージした通りに書けるからなんでしょうね。
ドキュメント読んだのですが、Androidみたいに参考になるコードないな....

Discussion