完成形
inputAccesorryViewにxibで作ったテキストの入力欄と送信ボタンを配置、
テキストを入力してボタンを押すとViewControllerにある表示用のTextViewにテキストを表示する。
ViewControllerへのテキストの受け渡しはDelegateで行う。
はじめに
StoryboardでNavigationControllerと入力したテキストを表示するTextViewを適当に配置
TextViewはViewController.swiftに"displayTextView"と言う名前でOutlet接続しておきます
1.xibファイルの作成
プロジェクトフォルダの任意の位置で、New File...を選択
Viewを選択してファイル名を入力してCreate
2.UIの作成
SizeをFreeFormに変更してフォームの形を適当にそれっぽくする。
メッセージを入力するTextViewとButtonを配置
TextViewの上下と左の制約を10にしてAdd Constraints
(下の制約はSafeAreaから指定するのがポイント)
ボタンのVertically in Containerをチェックして制約を追加
TextViewとButtonの縦センターを合わせる
上のButtonのVertically in Containerで設定した縦センターの制約の設定を下図の様に変更して
TextViewのセンターとButtonのセンターを合わせる
ボタンの左右と幅の制約をかける
TextViewのScrolling Enableのチェックを外す
以上で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を設定
作成しておいた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()
}
}
以上で終わりです
最後に
間違いなどありましたらご指摘いただけると幸いです