###完成形
inputAccesorryViewにxibで作ったテキストの入力欄と送信ボタンを配置、
テキストを入力してボタンを押すとViewControllerにある表示用のTextViewにテキストを表示する。
ViewControllerへのテキストの受け渡しはDelegateで行う。
##はじめに
StoryboardでNavigationControllerと入力したテキストを表示するTextViewを適当に配置
TextViewはViewController.swiftに"displayTextView"と言う名前でOutlet接続しておきます
##1.xibファイルの作成
####プロジェクトフォルダの任意の位置で、New File...を選択
##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クラスを作成しておく
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を接続してコーディング
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に表示する
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()
}
}
以上で終わりです
##最後に
間違いなどありましたらご指摘いただけると幸いです