채팅창을 만들어보고있는데 채팅창에서 메세지의 기본 ui는 구현을 했고 이제 다음은 메세지를 보내는 부분을 구현을 해봤다. 기본적으로 카카오톡 채팅을 보고 기능을 구현하려다 보니 생각해야할 부분이 많았다.
카카오톡 채팅창을 보면 우선
빈채팅창에 enter를 누르면 빈 채팅창이 위아래로 늘어나는걸 확인 할 수 있다. 그래서 처음에는 아무생각없이 textfield를 사용해야지 했는데 구글링을 해보니 2줄 이상의 text를 받을 때는 textview를 사용하는게 맞다고 해서 textview를 사용하기로 했고 데이터 전달방식은 delegate패턴을 이용했다
protocol MessageDelegate: AnyObject {
func sendMessage(message: ChatModel)
}
우선 프로토콜을 선언해주고
weak var delegate: MessageDelegate?
해당 프로토콜 타입의 변수를 weak으로 선언해준다(강한 참조를 방지하기 위해)
extension ChatTextView {
@objc func sendButtonTapped(_ sender: Any) {
self.delegate?.sendMessage(message: .init(content: chatTextView.text, date: "3월2일", send: true))
chatTextView.text = ""
sendButton.isHidden = true
}
}
그리고 버튼이 눌리면 delegate에 sendMessage를 실행시켜주는데 textview의 text를 인자로 넘겨준다. 처음엔 이렇게만 구현을 했는데 카카오톡에서는 메세지를 보내고나면 당연히 textview가 초기화가 되고 초기화가 된다는 뜻은 아무런 text가 없다는 뜻이므로 보내기 버튼도 활성화가 되면 안된다.
그리고 이 delegate는 viewController에서 선언해주면된다
chatView.chatTextView.delegate = self
viewcontroller에서 이 view의 textview 델리게이트의 권한을 viewcontroller로 넘겨준다고 선언하고
extension ViewController: MessageDelegate {
func sendMessage(message: ChatModel) {
viewModel.addData(message)
scrollToButton(animate: true)
}
}
이렇게 선언해주면된다. 여기서 scrollToBottom함수를 실행시켜준 이유는 카카오톡의 경우 스크롤이 어디있던 내가 send버튼을 눌러서 메세지를 보내면 scroll이 아래로 설정이 되고 여기에 animation이 들어가있길래 이렇게 구현을 했다
카카오톡 TextView를 보면 처음에는 1줄짜리 textView였다가 엔터를 누르거나 글자길이가 width를 넘기면 자동으로 2줄이상의 textview로 바뀌게 된다.
근데 카카오톡을 보면 또 4줄이상이 되면 textview가 scroll로 바뀐다.
이걸 구현하는게 진짜 개인적으로는 시간이 오래걸렸는데 우선생각을 해보면
1번을 먼저 생각해보면 autolayout을 잡을 때 이 높이가 일정길이 이상으로 커지면 안되겠구나라는 생각이 든다 그리고 일정길이는 기본 textview에서의 한줄길이의 곱하기 3이라고 생각하면 autolayout을 이렇게잡으면된다
chatView.snp.makeConstraints { make in
make.height.lessThanOrEqualTo(chatView.chatTextView.frame.height*3)
make.leading.trailing.equalToSuperview().inset(10)
make.bottom.equalToSuperview().inset(40)
}
lessThanOrEqualTo가 내가 생각하고 정의한바로는 "여기까지만 커지도록"으로 생각을 했다 그래서 원래 가지고있던 frame의 height의 3배까지만 커지고 커지지 마라 라고 정의를 했다
그리고 content에 맞게 높이가 늘어나려면 isScrollEnabled를 false로 설정해줘야한다 그래야 반응형으로 늘어난다
그래서 처음에는 이 textview의 길이가 60이상이면 isScrollEnabeld를 true로 하고 아니면 false로 해라라는 식으로 코딩을 했는데 이게 안먹는다...
textView.isScrollEnabled = chatView.frame.height <= 60 ? false : true
이런식으로 하니까 3줄이상부터 scroll이 되기시작하는데 문제는 백스페이스를 누르면 다시 textview의 높이가 줄어들지 않는다. 그래서 열심히 구글링을 해봤다...
주로 sizeThatFits은 Label, TextView 등 높이값을 유동적으로 조정하기 위해 많이 사용됩니다.
그리고 이런 글을 보게되었다. textview에서 유동적인 값을 조정하거나 얻을 수 있는 방법이라고 한다
func textViewDidChange(_ textView: UITextView) {
let estimatedSize = textView.sizeThatFits(CGSize(width: textView.frame.width, height: textView.frame.height))
textView.isScrollEnabled = estimatedSize.height <= 60 ? false : true
chatView.sendButton.isHidden = textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? true : false
}
이렇게 유동적인 높이값을 sizeThatFit으로 받아오고 그 height값에 따라서 분기처리를 해주니 잘 작동했다
코딩하는데 계속
AddInstanceForFactory: No factory registered for id ~~~~
이런 메세지가 콘솔창에 뜨길래 너무 거슬려서 없애는 방법을 찾게되었다