LoginSignup
1
1

More than 3 years have passed since last update.

メッセージ送信用InputAccesorryViewの作成

Last updated at Posted at 2021-01-16

完成形

inputAccesorryViewにxibで作ったテキストの入力欄と送信ボタンを配置、
テキストを入力してボタンを押すとViewControllerにある表示用のTextViewにテキストを表示する。

ViewControllerへのテキストの受け渡しはDelegateで行う。

スクリーンショット 2020-12-13 10.14.42.png

はじめに

StoryboardでNavigationControllerと入力したテキストを表示するTextViewを適当に配置
TextViewはViewController.swiftに"displayTextView"と言う名前でOutlet接続しておきます

スクリーンショット 2020-12-08 20.46.35.png

1.xibファイルの作成

プロジェクトフォルダの任意の位置で、New File...を選択

スクリーンショット 2020-12-08 20.52.00.png

Viewを選択してファイル名を入力してCreate

スクリーンショット 2020-12-08 20.56.23.png

2.UIの作成

SizeをFreeFormに変更してフォームの形を適当にそれっぽくする。
スクリーンショット 2020-12-08 21.10.27.png

メッセージを入力するTextViewとButtonを配置

TextViewの上下と左の制約を10にしてAdd Constraints
(下の制約はSafeAreaから指定するのがポイント)

スクリーンショット 2020-12-08 21.20.12.png

ボタンのVertically in Containerをチェックして制約を追加

スクリーンショット 2020-12-08 21.27.40.png

TextViewとButtonの縦センターを合わせる

上のButtonのVertically in Containerで設定した縦センターの制約の設定を下図の様に変更して
TextViewのセンターとButtonのセンターを合わせる
スクリーンショット 2020-12-08 21.37.47.png

ボタンの左右と幅の制約をかける

スクリーンショット 2020-12-08 22.29.00.png

TextViewのScrolling Enableのチェックを外す

スクリーンショット 2020-12-09 22.26.41.png

以上でUIの作成は終わり

3.xib用のUIViewのクラスを作成

swiftファイルを作成して、以下のコードを入力

ひとまずxibに設定できるように仮でUIViewクラスを作成しておく

MsgInputAccessoryView.swift
import UIKit

class MsgInputAccessoryView: UIView {

  override init(frame: CGRect) {
    super.init(frame: frame)
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

xibのFile's OwnerにUIViewのClassを設定

スクリーンショット 2020-12-09 21.58.37.png

作成しておいたUIView ClassにUIを接続してコーディング

MsgInputAccessoryView.swift
import UIKit

//入力したtextをViewControllerに伝えるDelegate (:classは循環参照防止)
protocol MsgInputAccessoryViewDelegate :class {
  func tapedSendButton(text: String)

}

class MsgInputAccessoryView: UIView {

  @IBOutlet weak var msgTextView: UITextView!
  @IBOutlet weak var sendButton: UIButton!

  //sendButtonが押されたときに呼ばれる
  @IBAction func tapedSendButton(_ sender: Any) {

    guard let text = msgTextView.text else { return }
    //delegateに入力した値を渡す
    delegate?.tapedSendButton(text: text)

  }

  weak var delegate : MsgInputAccessoryViewDelegate?


  override init(frame: CGRect) {
    super.init(frame: frame)

    //viewの貼り付け
    nibInit()
    setupViews()
    //msgTextViewの高さを可変にする設定①
    autoresizingMask = .flexibleHeight
  }


  private func setupViews(){

    msgTextView.layer.cornerRadius = 15
    //未入力では押せない様にしておく
    sendButton.isEnabled = false

    //初期は空欄にしておく
    msgTextView.text = ""
    msgTextView.delegate = self

  }

  //send後の処理(ViewControllerから実行)
  func removeText(){

    msgTextView.text = ""
    sendButton.isEnabled = false
  }

  //msgTextViewの高さを可変にする設定②
  override var intrinsicContentSize: CGSize{
    return .zero
  }

  //xibのロードメソッド
  private func nibInit(){

    let nib = UINib(nibName: "MsgInputAccessoryView", bundle: nil)
    //xibのFile's Ownerにclassを紐付ける
    guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }

    view.frame = self.bounds
    //親のViewサイズが変わった時に、子のViewサイズや位置を自動的に調整できる様に設定
    view.autoresizingMask = [.flexibleHeight,.flexibleWidth]

    //ただのUIViewなので、UINib.instantiate(self).firstから取得しProfileViewに対してaddSubviewする
    self.addSubview(view)
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}

extension MsgInputAccessoryView: UITextViewDelegate{
  //textViewが編集されるたびに呼ばれる
  func textViewDidChange(_ textView: UITextView) {
    if textView.text.isEmpty {
      //inputTextViewが空欄だったらsendButtonを無効化にする
      sendButton.isEnabled = false

    }else{
      sendButton.isEnabled = true

    }
  }
}

4.受け取ったテキストを表示するViewControllerのコーディング

InputAccessoryViewにセットして、Delegateでテキストを受け取ったテキストをTextViewに表示する

ViewController.swift
import UIKit

class ViewController: UIViewController {

  @IBOutlet weak var displayTextView: UITextView!
  //viewにframeサイズを与えてインスタンス化(クロージャー式 定義と同時にプロパティーに値を与える)
  //lazyをつけてdelegateでselfにアクセスできる様にする
  private lazy var msgInputAccessoryView: MsgInputAccessoryView = {

    let view  = MsgInputAccessoryView()
    view.frame = .init(x: 0, y: 0, width: view.frame.width, height: 100)
    view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 100)
    //MsgInputAccessoryViewで設定したdelegate
    view.delegate = self
    return view

  }()


  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
  }


  //viewControllerに元々あるinputAccessoryViewにUIViewをセット
  override var inputAccessoryView: UIView?{

   // get{
      return msgInputAccessoryView
    //}
  }

  //初めからmsgInputAccessoryViewが表示される様に
  //ViewController(self)のcanBecomeFirstResponderをtrueに書き換え
  override var canBecomeFirstResponder: Bool{
    return true

  }
}

//MsgInputAccessoryViewからdelegateで値を受け取る
extension ViewController: MsgInputAccessoryViewDelegate{
  func tapedSendButton(text: String) {
    print(text)

    displayTextView.text = text

    //値を受け取った時点で、msgTextViewのクリアを実行
    msgInputAccessoryView.removeText()

  }
}

以上で終わりです

最後に

間違いなどありましたらご指摘いただけると幸いです

1
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
1
1