안녕하세요!
우리가 카카오톡을 사용할 때 아래 영상처럼 채팅을 치기 위해선 키보드(소프트)를 사용해야합니다.
영상을 자세히 보시면 키보드가 채팅이 입력되는 공간을 가리지 않고 밀어내는 것을 확인할 수 있습니다.
이런 동작을 Keyboard Avoidance라고 합니다.
일전 SwiftUI를 사용하여 키보드 어보이던스를 피하는 글을 작성한 적이 있었는데요
UIKit같은 경우 SwiftUI와 달리 키보드 어보이던스가 자동으로 실행되지 않습니다.
(자동으로 키보드 어보이던스가 적용되는 SwiftUI는 해당 기능을 끄는 것이 까다롭습니다.. UIKit 최고 🙌)
아래 영상은 제가 직접 구현한 채팅창 화면입니다.
먼저 입력영역은 UITextView로 구현하였습니다.
카카오톡같은 경우는 멀티라인 입력을 지원하기 때문에 한줄입력밖에 안되는 UITestField보단
UITextView가 적합하다고 판단하였습니다.
UITextView가 First responder가 되면 소프트 키보드가 화면상에 등장하게 됩니다.
해당 이벤트는 NotificationCenter를 사용하여 포착할 수 있습니다.
UIResponder.keyboardWillShowNotification의 경우 키보드가 등장하기전 호출되고
UIResponder.keyboardWillHideNotification의 경우 키보드가 사라지기전 호출됩니다.
(First responder에서 해제될 때)
Notification정보를 통해서 키보드가 등장하는 애니메이션의 duration과
키보드가 등장한 이후 키보드 Frame정보를 획들할 수 있습니다.
해당 정보들을 사용하여 입력창과 채팅내역을 보여주는 뷰를 원하는 만큼 밀어내는 방식을 사용했습니다.
밀어내는 방법으로는 transform을 사용하였습니다.
transform을 변형하는 경우 AutoLayout에 영향을 끼치지 않음으로
다른 뷰들에 영향을 주지않고 필요한 뷰에만 키보드 어보이던스를 적용할 수 있다는 장점이 있습니다.
UITextView
해당 예제를 구현하는데 가장 까다로웠던 것은 UITextView의 Inset들이였습니다.
우선 UITextView는 스크롤과 관련된 옵션이 존재합니다.
스크롤 기능을 사용하는 경우 내부적으로 instrinsicSize를 가지지 않아 레이아웃을 직접 설정해줘야 합니다.
스크롤을 사용하지 않는 경우 기본적으로 한줄크기의 기본 사이즈를 가지며, 라인이 증가될 수록 그 값도 커집니다.
텍스트 뷰는 contentInset, textContainerInset 두종류의 인셋을 사용할 수 있습니다.
contentInset는 내부 컨텐츠(스크롤 뷰 사용시)에 적용되는 인셋 입니다.
해당 인셋을 UITextView가 사용할 수 있는 이유는 UITextView가 UIScrollView를 상속하기 때문입니다.
contentInset은 텍스트 필드가 스크롤을 사용할 때 정상적으로 동작합니다.
만약 스크롤을 사요중이 아닌데 해당 값을 설정하는 경우 UI가 의도대로 동작하지 않습니다.
textContainerInset는 실제로 텍스트가 입력되는 요소와 텍스트 컨테이너간의 인셋입니다.
해당 값은 UITextView자체 프로퍼티로 스크롤 여부에 관계 없이 사용이 가능합니다.
안쪽에 빨간색 화살표는 lineFragmentPadding프로퍼티로 설정할 수 있으며, 기본값이 5입니다.
아래코드는 예시에 적용된 코드입니다.
예시 프로젝트 레포지토리를 남겨놓겠습니다.
Tuist로 구현한 프로젝트라 tuist generate후 돌려보시길 바랍니다 감사합니다~!
참고한 UITextView관련 포스팅입니다.
'UIKit' 카테고리의 다른 글
[UIKit] UIViewController, modal 화면표시에 대해서(+커스텀) (1) | 2024.09.05 |
---|---|
[UIKit] 커스텀 탭바 만들기 (0) | 2024.04.29 |
[UIKit] convert매서드를 이용한 상대 좌표 구하기 (0) | 2024.04.01 |
[UIKit] UIKit 앱실행부터 UIView까지(iOS 13 ⬆) (0) | 2024.03.12 |