Place the text input field and send button made with xib in inputAccesorryView, When you enter text and press the button, the text is displayed in the TextView for display in the view controller.
Delegate is used to transfer text to the view controller.
Arrange TextView appropriately to display the text entered as NavigationController in Storyboard TextView has an Outlet connection to ViewController.swift with the name "displayTextView"
Change the Size to FreeForm to make the form look like it.
Add Constraints with 10 constraints on the top, bottom and left of the TextView (The point is to specify the restrictions below from the Safe Area)
Change the vertical center constraint setting in the Button's Vertically in Container above as shown in the figure below. Align the center of the TextView with the center of the Button
This is the end of UI creation
Temporarily create a UIView class so that it can be set to xib for the time being
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")
}
}
MsgInputAccessoryView.swift
import UIKit
//Delegate tells the input text to the view controller(:class is circular reference prevention)
protocol MsgInputAccessoryViewDelegate :class {
func tapedSendButton(text: String)
}
class MsgInputAccessoryView: UIView {
@IBOutlet weak var msgTextView: UITextView!
@IBOutlet weak var sendButton: UIButton!
//Called when sendButton is pressed
@IBAction func tapedSendButton(_ sender: Any) {
guard let text = msgTextView.text else { return }
//Pass the value entered in delegate
delegate?.tapedSendButton(text: text)
}
weak var delegate : MsgInputAccessoryViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
//Paste view
nibInit()
setupViews()
//Setting to make the height of msgTextView variable ①
autoresizingMask = .flexibleHeight
}
private func setupViews(){
msgTextView.layer.cornerRadius = 15
//Make sure you can't press it without input
sendButton.isEnabled = false
//Leave blank initially
msgTextView.text = ""
msgTextView.delegate = self
}
//Post-send processing(Executed from ViewController)
func removeText(){
msgTextView.text = ""
sendButton.isEnabled = false
}
//Setting to make the height of msgTextView variable ②
override var intrinsicContentSize: CGSize{
return .zero
}
//xib load method
private func nibInit(){
let nib = UINib(nibName: "MsgInputAccessoryView", bundle: nil)
//xib File's Associate class with Owner
guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }
view.frame = self.bounds
//Set so that the view size and position of the child can be adjusted automatically when the view size of the parent changes.
view.autoresizingMask = [.flexibleHeight,.flexibleWidth]
//It's just a UIView, so UINib.instantiate(self).Get from first and addSubview to ProfileView
self.addSubview(view)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension MsgInputAccessoryView: UITextViewDelegate{
//Called every time textView is edited
func textViewDidChange(_ textView: UITextView) {
if textView.text.isEmpty {
//Disable sendButton if inputTextView is blank
sendButton.isEnabled = false
}else{
sendButton.isEnabled = true
}
}
}
Set to InputAccessoryView and display the text received by Delegate in TextView
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var displayTextView: UITextView!
//Instantiate by giving frame size to view(Give a value to the property at the same time as the closure expression definition)
//Add lazy so that you can access self with delegate
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)
//Delegate set in MsgInputAccessoryView
view.delegate = self
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
//Set UIView to the original inputAccessoryView in viewController
override var inputAccessoryView: UIView?{
// get{
return msgInputAccessoryView
//}
}
//MsgInputAccessoryView is displayed from the beginning
//ViewController(self)Rewrite canBecomeFirstResponder to true
override var canBecomeFirstResponder: Bool{
return true
}
}
//Receive value with delegate from MsgInputAccessoryView
extension ViewController: MsgInputAccessoryViewDelegate{
func tapedSendButton(text: String) {
print(text)
displayTextView.text = text
//When the value is received, clear msgTextView
msgInputAccessoryView.removeText()
}
}
That's it
I would appreciate it if you could point out any mistakes.