UIToolBarに上下ボタンや完了ボタンをつけるExtension

# はじめに

ある入力フォームで、キーボードの上に、上下ボタンや完了ボタンがついているのをよく見かけます。そういう気遣いほんとありがたい :hugging:
今回は、一文追加するだけで、それらを実装してくれるExtensionを作ってみたのでそれを紹介します。

# 実装後イメージ

## 完了ボタンのみ

![uitoolbar_done.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/3f94d77b-9526-445a-e4e6-14bb4a2e65e7.gif)

## 上下ボタンと完了ボタン
 
![uitoolbar_updowndone.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/aed1f3aa-1538-d3df-4cb8-5894f16c7607.gif)

# 使い方

## 完了ボタンのみ

```swift
override func viewDidLoad() {
    super.viewDidLoad()
    // 対象のテキストフィールドがアクティブなとき、キーボードのツールバーに、完了ボタンを設定する。
    addPreviousNextableDoneButtonOnKeyboard(textFields: [textField1], previousNextable: false)
}
```

## 上下ボタンと完了ボタン

```swift
override func viewDidLoad() {
    super.viewDidLoad()
    // 対象のテキストフィールドがアクティブなとき、キーボードのツールバーに、前後ボタンや完了ボタンを設定する。
    addPreviousNextableDoneButtonOnKeyboard(textFields: [textField2, textField3], previousNextable: true)
}
```

# Extension のコード全体

なお、ここに載せているコードは、以下のGistで公開しています。
[mnaruse/ViewController+ToolBar.swift](
https://gist.github.com/mnaruse/0146b10ef030edd5561e9272ab12f5a9)

```swift

//
//  ViewController+ToolBar.swift
//  KeyboardUpDownSample
//
//  Created by Miharu Naruse on 2020/11/15.
//

// 参考元サイト
// - URL:: https://stackoverflow.com/questions/14148276/toolbar-with-previous-and-next-for-keyboard-inputaccessoryview

import Foundation
import UIKit

extension UIViewController {
    /// 対象のテキストフィールドがアクティブなとき、キーボードのツールバーに、前後ボタンや完了ボタンを設定する処理。
    /// - Parameters:
    ///   - textFields: 設定したいテキストフィールドの配列
    ///   - previousNextable: 前後ボタンを有効にするか否か
    ///
    /// 使い方
    /// =============================================
    ///     // テキストフィールドのキーボードのツールバーの設定
    ///     addPreviousNextableDoneButtonOnKeyboard(textFields: [textField1], previousNextable: false)
    ///     addPreviousNextableDoneButtonOnKeyboard(textFields: [textField2, textField3], previousNextable: true)
    ///
    func addPreviousNextableDoneButtonOnKeyboard(textFields: [UITextField], previousNextable: Bool = false) {
        for (index, textField) in textFields.enumerated() {
            // テキストフィールドごとにループ処理を行う。
            let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
            toolBar.barStyle = .default
            /// バーボタンアイテム
            var items = [UIBarButtonItem]()

            // MARK: 前後ボタンの設定

            if previousNextable {
                // 前後ボタンが有効な場合
                /// 上矢印ボタン
                let previousButton = UIBarButtonItem(image: UIImage(systemName: "chevron.up"), style: .plain, target: self, action: nil)
                if textField == textFields.first {
                    // 設定したいテキストフィールドの配列のうち、一番上のテキストフィールドの場合、不活性化させる。
                    previousButton.isEnabled = false
                } else {
                    // 上記以外の場合
                    // １つ前のテキストフィールドをターゲットに設定する。
                    previousButton.target = textFields[index - 1]
                    // ターゲットにフォーカスを当てる。
                    previousButton.action = #selector(UITextField.becomeFirstResponder)
                }

                /// 固定スペース
                let fixedSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: self, action: nil)
                fixedSpace.width = 8

                /// 下矢印ボタン
                let nextButton = UIBarButtonItem(image: UIImage(systemName: "chevron.down"), style: .plain, target: self, action: nil)
                if textField == textFields.last {
                    // 設定したいテキストフィールドの配列のうち、一番下のテキストフィールドの場合、不活性化させる。
                    nextButton.isEnabled = false
                } else {
                    // 上記以外の場合
                    // １つ後のテキストフィールドをターゲットに設定する。
                    nextButton.target = textFields[index + 1]
                    // ターゲットにフォーカスを当てる。
                    nextButton.action = #selector(UITextField.becomeFirstResponder)
                }

                // バーボタンアイテムに前後ボタンを追加する。
                items.append(contentsOf: [previousButton, fixedSpace, nextButton])
            }

            // MARK: 完了ボタンの設定

            let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
            let doneButton = UIBarButtonItem(title: "完了", style: .done, target: view, action: #selector(UIView.endEditing))
            // バーボタンアイテムに完了ボタンを追加する。
            items.append(contentsOf: [flexSpace, doneButton])

            toolBar.setItems(items, animated: false)
            toolBar.sizeToFit()

            textField.inputAccessoryView = toolBar
        }
    }
}
```

# 参考記事

- Gist
    - [mnaruse/ViewController+ToolBar.swift](
https://gist.github.com/mnaruse/0146b10ef030edd5561e9272ab12f5a9)
- 参考元サイト
    -  [【stackoverflow】Toolbar with “Previous” and “Next” for Keyboard inputAccessoryView](https://stackoverflow.com/questions/14148276/toolbar-with-previous-and-next-for-keyboard-inputaccessoryview)