10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

watnow Advent CalendarAdvent Calendar 2021

Day 25

【Swift】InputAccessoryViewを使ってメッセージ入力を実装する

Posted at

はじめに

初めまして!
関西を拠点に活動している学生団体watnowの、アドベントカレンダー最終日を担当させていただきますアントニーと申します!

今回はチャット機能実装などの際に必要不可欠となる、メッセージ入力画面/機能を実装する簡単な方法を紹介させていただきます。

InputAccessoryViewとは

UITextFieldやUITextViewを使用する際に出てくるキーボードにViewをアタッチするために使用します。
簡単に言うと、チャットで文章を送信するときの機能を簡単に作成できるんだなって思ってくれたら良いと思います。

今回実装したいこと

こちらが今回の完成形です。
文字を入力し、送信ボタンを押すとLabelに入力した文字が表示されます。
InputAccessoryview.gif

実装

まずはじめに、Xibファイルを作成します。
ViewのsizeはFreeformにしておきましょう。
スクリーンショット 2021-12-25 22.22.22.png

上記で作成したXibファイルに紐付けるswiftファイルを作成します。
スクリーンショット 2021-12-25 22.19.11.png

画面作成

以下のようにUITextViewとUIButtonを配置します。
※オートレイアウトの設定を忘れないでください。
スクリーンショット 2021-12-25 22.25.35.png

コード説明

ここから、コードの説明をしていきます。
全体のコードは最後に記載してますので、お急ぎの方はそちらをご参照ください。

まず、作成したswiftファイル(ここでは、"IndicateAccessoryView.swift"と名付けました。)に、以下のようにクラスを定義します。

IndicateAccessoryView.swift
import UIKit

class IndicateAccessoryView: UIView {
    
    @IBOutlet var inputTextView: UITextView!
    @IBOutlet var sendButton: UIButton!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

TextViewの高さを可変にする

IndicateAccessoryView.swift
 override init(frame: CGRect) {
        super.init(frame: frame)
        
        autoresizingMask = .flexibleHeight
    }

    override var intrinsicContentSize: CGSize {
        return .zero
    }

Delegateを作成する

IndicateAccessoryView.swift
protocol IndicateAccessoryViewDelegate: class {
    func tappedSendButton(text: String)
}

XibファイルをIndidateInputAccessoryViewに表示する

以下のコードでXibファイルをViewに表示する処理を行なっています。

IndicateAccessoryView.swift
private func nibInit() {
        let nib = UINib(nibName: "IndicateAccessoryView", bundle: nil)
        guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }
        
        view.frame = self.bounds
        view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        self.addSubview(view)
    }

IndicateAccessoryViewの全文

IndicateAccessoryView.swift
import UIKit


protocol IndicateAccessoryViewDelegate: class {
    func tappedSendButton(text: String)
}

class IndicateAccessoryView: UIView {
    
    @IBOutlet var inputTextView: UITextView!
    @IBOutlet var sendButton: UIButton!
    
    var delegate: IndicateAccessoryViewDelegate?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        nibInit()
        autoresizingMask = .flexibleHeight
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    @IBAction func tappedSendButton() {
        guard let text = inputTextView.text else { return }
        delegate?.tappedSendButton(text: text)  //textViewの情報を渡す準備
    }
    //chatTextViewの高さを可変にする(initでautoresizingMaskの設定必要)
    override var intrinsicContentSize: CGSize {
        return .zero
    }
    
    //XibファイルをChatInputAccessoryViewに表示するためのメソッド
    private func nibInit() {
        let nib = UINib(nibName: "IndicateAccessoryView", bundle: nil)
        guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }
        
        view.frame = self.bounds
        view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        self.addSubview(view)
    }
    
    
}

紐付け

Xibファイルとswiftファイルの紐付けですが、Viewではなく、PlaceholdersのFile's Ownerに紐づけるように注意してください。
スクリーンショット 2021-12-25 22.41.55.png

MainStoryboardの設定

以下のように、送信したボタンを表示するラベルを配置しました。
スクリーンショット 2021-12-25 22.45.36.png

ViewController.swiftのコード説明

InputAccessoryViewの配置

以下のコードで配置します。

IndicateAccessoryView.swiftで作成しているので、その設定も行います。

ViewController.swift
private lazy var indicateAccessoryView: IndicateAccessoryView = {
        let view = IndicateAccessoryView()
        view.frame = .init(x: 0, y: 0, width: view.frame.width, height: 150)
        view.delegate = self
        return view
    }()

override var inputAccessoryView: UIView? {
        get {
            return indicateAccessoryView
        }
    }

override var canBecomeFirstResponder: Bool {
        return true
    }

 送信ボタンがタップされた際、入力された文字を作成したラベルに表示するようにします。

ViewController.swift
extension ViewController: IndicateAccessoryViewDelegate {
    func tappedSendButton(text: String) {
        sendLabel.text = text
    }
}

コード全文

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet var sendLabel: UILabel!
    
    private lazy var indicateAccessoryView: IndicateAccessoryView = {
        let view = IndicateAccessoryView()
        view.frame = .init(x: 0, y: 0, width: view.frame.width, height: 150)
        view.delegate = self
        return view
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override var inputAccessoryView: UIView? {
        get {
            return indicateAccessoryView
        }
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }
}

extension ViewController: IndicateAccessoryViewDelegate {
    func tappedSendButton(text: String) {
        sendLabel.text = text
    }
}

#終わりに
いかがでしたでしょうか。
文字入力する際に、キーボードも出てきてくれるし、消える時も一緒に消えてくれるし、すごく便利ではないでしょうか。
今回の実装では簡単化のために、cornerRadiusや送信後にtextViewのクリアなどは行いませんでしたが、これでかなり本格的なチャット機能を実装できるのではないでしょうか。

10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?