스위프트, UIKit 에서 테이블 뷰 내 텍스트뷰 높이 조절
지금 당근마켓의 내물건 팔기를 구현하고 있습니다. 전체적으로 UITableView로 만들고 각 셀마다 맞는 셀을 구현했습니다. 텍스트 뷰에 글을 작성하면 텍스트뷰의 높이가 글자 수에 맞춰 늘어나는데, 이때 키보드는 화면 하단에 고정되어 있는것으로 판단됩니다. 그래서 아래와 같이 구현해봤습니다. class FeedViewController: UIViewController {
// MARK: - Variable
private let tableSection: [String] = ["이미지", "제목", "내용"]
var selectedImages: [UIImage] = []
// MARK: - UI Components
private let feedTableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.separatorStyle = .none
tableView.showsVerticalScrollIndicator = false
tableView.alwaysBounceVertical = false
tableView.isScrollEnabled = true
return tableView
}()
...
// MARK: - Layout
private var feedTableViewBottomConstraint: NSLayoutConstraint!
private var registerButtonTopConstraint: NSLayoutConstraint!
private func configureConstraints() {
view.addSubview(feedTableView)
view.addSubview(registerFeedButton)
feedTableView.translatesAutoresizingMaskIntoConstraints = false
registerFeedButton.translatesAutoresizingMaskIntoConstraints = false
// 제약 조건 저장
feedTableViewBottomConstraint = feedTableView.bottomAnchor.constraint(equalTo: registerFeedButton.topAnchor, constant: -10)
registerButtonTopConstraint = registerFeedButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10)
NSLayoutConstraint.activate([
// 테이블뷰 제약조건
feedTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
feedTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
feedTableView.topAnchor.constraint(equalTo: view.topAnchor),
feedTableViewBottomConstraint,
// 버튼 제약조건
registerFeedButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15),
registerFeedButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -15),
registerFeedButton.heightAnchor.constraint(equalToConstant: 50),
registerButtonTopConstraint
])
// 키보드 노티피케이션 설정
setupKeyboardNotifications()
}
private func setupKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc private func keyboardWillShow(_ notification: Notification) {
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
// 키보드가 올라오면 테이블뷰의 bottom을 키보드의 top에 맞춤
feedTableViewBottomConstraint.constant = -keyboardFrame.height + 100
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
}
@objc private func keyboardWillHide(_ notification: Notification) {
// 키보드가 내려가면 테이블뷰의 bottom을 버튼의 top으로 복원
feedTableViewBottomConstraint.constant = -10
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
} 그리고 ContentInputCell 이라고해서 텍스트뷰를 입력하는 곳에는 아래와 같이 작성했습니다. // MARK: - UI Component
private let contentTextView: UITextView = {
let textView = UITextView()
textView.text = "오늘 하루는 어땠나요? 😀"
textView.backgroundColor = .systemBackground
textView.layer.cornerRadius = 5
textView.layer.masksToBounds = true
// 글자 수에 따라 크기가 늘어가게 하기 위함
textView.isScrollEnabled = false
textView.textAlignment = .left
textView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
textView.textColor = .secondaryLabel
textView.backgroundColor = .systemBackground
textView.font = UIFont.systemFont(ofSize: 16, weight: .bold)
return textView
}()
...
private func configureConstraints() {
contentView.addSubview(contentTextView)
contentTextView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentTextView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
contentTextView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
contentTextView.topAnchor.constraint(equalTo: contentView.topAnchor),
contentTextView.bottomAnchor.constraint(equalTo: contentView.keyboardLayoutGuide.topAnchor, constant: 5),
contentTextView.heightAnchor.constraint(greaterThanOrEqualToConstant: 350)
])
}
// MARK: - Extension: UITextViewDelegate
extension ContentInputCell: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
guard let tableView = tableView else { return }
let contentSize = textView.sizeThatFits(CGSize(width: textView.bounds.width, height: .infinity))
if textView.bounds.height != contentSize.height {
tableView.contentOffset.y += contentSize.height - textView.bounds.height
UIView.setAnimationsEnabled(false)
tableView.beginUpdates()
tableView.endUpdates()
UIView.setAnimationsEnabled(true)
}
}
}
extension ContentInputCell {
var tableView: UITableView? {
var view = superview
while view != nil && !(view is UITableView) {
view = view?.superview
}
return view as? UITableView
}
}