markdown

はじめに (対象読者・この記事でわかること)

この記事は、SwiftでiOSアプリを開発している方で、キーボード上部に独自のツールバーを追加して文字を挿入したい方を対象としています。特に、メールアドレスや住所、定型文などを頻繁に入力するフォームを持つアプリを開発している方に役立ちます。

この記事を読むことで、UITextFieldやUITextViewにカスタムツールバーを追加する方法、ツールバーにボタンを配置してタップ時に特定の文字列を挿入する方法、さらに複数のテキスト入力フィールドでツールバーを共有する方法まで、実用的なテクニックを習得できます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Swiftの基本的な文法 - UIKitを使ったiOSアプリ開発の基礎知識 - UITextFieldやUITextViewの基本的な使い方

なぜカスタムツールバーが必要なのか

iOSのデフォルトのキーボードには、特定の文字や記号が不足していることがあります。特に、日本語入力時に「@」や「.com」などを入力するのは若干面倒です。また、住所や電話番号、メールアドレスなど、繰り返し入力する情報がある場合、毎回手入力するのは効率的ではありません。

カスタムツールバーを実装することで、以下のようなメリットがあります: - よく使う文字や記号をワンタップで入力できる - 定型文を簡単に挿入できる - ユーザー体験の向上につながる - 入力ミスの削減

カスタムツールバーの実装方法

ここからは、実際にカスタムツールバーを実装していきます。シンプルな例から始めて、徐々に機能を追加していきましょう。

基本的なツールバーの作成

まず、UITextFieldに最もシンプルなツールバーを追加する方法を見ていきます。

Swift
import UIKit class ViewController: UIViewController { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() setupToolbar() } private func setupToolbar() { // ツールバーの作成 let toolbar = UIToolbar() toolbar.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44) // ボタンアイテムの作成 let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneButton = UIBarButtonItem(title: "完了", style: .done, target: self, action: #selector(dismissKeyboard)) // ツールバーにアイテムを設定 toolbar.items = [space, doneButton] // テキストフィールドのinputAccessoryViewに設定 textField.inputAccessoryView = toolbar } @objc private func dismissKeyboard() { view.endEditing(true) } }

文字挿入ボタンを追加する

次に、特定の文字を挿入するボタンを追加してみましょう。

Swift
private func setupToolbar() { let toolbar = UIToolbar() toolbar.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44) // 文字挿入ボタン let atMarkButton = UIBarButtonItem(title: "@", style: .plain, target: self, action: #selector(insertAtMark)) let comButton = UIBarButtonItem(title: ".com", style: .plain, target: self, action: #selector(insertCom)) let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneButton = UIBarButtonItem(title: "完了", style: .done, target: self, action: #selector(dismissKeyboard)) toolbar.items = [atMarkButton, comButton, space, doneButton] textField.inputAccessoryView = toolbar } @objc private func insertAtMark() { insertText("@") } @objc private func insertCom() { insertText(".com") } private func insertText(_ text: String) { // 現在フォーカスが当たっているテキストフィールドを取得 if let activeTextField = findFirstResponder() as? UITextField { if let selectedRange = activeTextField.selectedTextRange { activeTextField.replace(selectedRange, withText: text) } } } private func findFirstResponder() -> UIResponder? { func find(in view: UIView) -> UIResponder? { if view.isFirstResponder { return view } for subview in view.subviews { if let responder = find(in: subview) { return responder } } return nil } return find(in: view) }

複数のテキストフィールドで共有する

複数のテキストフィールドで同じツールバーを使いたい場合は、以下のように実装します。

Swift
class ViewController: UIViewController { @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var domainTextField: UITextField! private var toolbar: UIToolbar! override func viewDidLoad() { super.viewDidLoad() setupSharedToolbar() } private func setupSharedToolbar() { toolbar = UIToolbar() toolbar.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44) // よく使うメールアドレスのボタン let email1 = UIBarButtonItem(title: "gmail.com", style: .plain, target: self, action: #selector(insertGmail)) let email2 = UIBarButtonItem(title: "yahoo.co.jp", style: .plain, target: self, action: #selector(insertYahoo)) let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneButton = UIBarButtonItem(title: "完了", style: .done, target: self, action: #selector(dismissKeyboard)) toolbar.items = [email1, email2, space, doneButton] // 複数のテキストフィールドで共有 emailTextField.inputAccessoryView = toolbar domainTextField.inputAccessoryView = toolbar } @objc private func insertGmail() { insertText("@gmail.com") } @objc private func insertYahoo() { insertText("@yahoo.co.jp") } }

ハマった点やエラー解決

実装中に遭遇する代表的な問題をいくつか紹介します。

問題1: 文字が重複して挿入される

Swift
// 悪い例 @objc private func insertCom() { textField.text? += ".com" // 現在のフォーカスがわからない }

この方法だと、どのテキストフィールドに挿入すべきかが明確でないため、意図しない動作になります。

問題2: 日本語入力中に文字が消える

日本語入力中にツールバーから文字を挿入すると、変換中の文字が消えてしまうことがあります。

解決策

現在のフォーカスを正確に取得し、selectedTextRangeを使用して文字を挿入することで、これらの問題を解決できます。

Swift
private func insertText(_ text: String) { // 現在のFirstResponderを取得 guard let responder = findFirstResponder() else { return } if let textField = responder as? UITextField { insertTextToTextInput(textField, text: text) } else if let textView = responder as? UITextView { insertTextToTextInput(textView, text: text) } } private func insertTextToTextInput(_ textInput: UITextInput, text: String) { guard let selectedRange = textInput.selectedTextRange else { return } textInput.replace(selectedRange, withText: text) }

より高度な実装

定型文を選択できるようにする例を紹介します。

Swift
class AdvancedToolbarViewController: UIViewController { @IBOutlet weak var textView: UITextView! private let phrases = [ "お疲れ様です。", "ありがとうございます。", "承知いたしました。", "よろしくお願いいたします。" ] private func setupAdvancedToolbar() { let toolbar = UIToolbar() toolbar.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44) var items: [UIBarButtonItem] = [] // 定型文ボタンを作成 for (index, phrase) in phrases.enumerated() { let button = UIBarButtonItem(title: "定型文\(index + 1)", style: .plain, target: self, action: #selector(insertPhrase(_:))) button.tag = index items.append(button) } let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneButton = UIBarButtonItem(title: "完了", style: .done, target: self, action: #selector(dismissKeyboard)) items.append(contentsOf: [space, doneButton]) toolbar.items = items textView.inputAccessoryView = toolbar } @objc private func insertPhrase(_ sender: UIBarButtonItem) { guard sender.tag < phrases.count else { return } insertText(phrases[sender.tag]) } }

まとめ

本記事では、SwiftでiOSアプリにカスタムキーボードツールバーを実装する方法を解説しました。

  • ツールバーの基本的な作成方法
  • 文字挿入ボタンの実装
  • 複数のテキストフィールドでの共有方法
  • よくある問題とその解決策

この記事を通して、ユーザーがより快適に入力できるアプリを開発できるようになりました。カスタムツールバーは、フォーム入力が多いアプリでは特に有効で、ユーザー体験の大幅な向上につながります。

今後は、ツールバーのカスタマイズ方法(色やフォントの変更)や、iPadでのマルチウィンドウ対応についても記事にする予定です。

参考資料