Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 리펙토링
- Xcode
- Human interface guide
- SWIFT
- UITextView
- rxswift
- tableView
- HIG
- UICollectionView
- collectionview
- swiftUI
- MVVM
- map
- uitableview
- Refactoring
- 리팩토링
- 리펙터링
- 클린 코드
- clean architecture
- combine
- swift documentation
- Observable
- Protocol
- Clean Code
- uiscrollview
- RxCocoa
- 스위프트
- 애니메이션
- ios
- ribs
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 키보드와 동시에 뷰 올리는 방법 (키보드와 특정 뷰 사이 거리 유지) 본문
키보드와 동시에 뷰 올리기
- "키보드와 텍스트필드 거리가 최소 50은 유지해주세요"
- 키보드가 올라가는 동시에, 키보드 상단과 텍스트 필드 하단의 거리가 최소 50이상 되도록하는 방법?
ex) 스크롤 처리를 해주지 않으면 키보드가 올라가고 아무런 처리가 없는 경우 텍스트필드가 영역이 가려짐
키보드와 동시에 뷰 올리는 방법
- autolayout을 사용한다면 keyboard safe area를 사용하거나 scrollView.contentInset.bottom를 동적으로 수정해주어도 되지만 다른 방법이 존재
- 키보드가 올라갈 때, 텍스트필드의 maxY좌표와 키보드의 높이를 계산해서 scrollView.setContentOffset(_:animated:)를 사용해도 자연스럽게 동작
구현
- 뷰 준비
- 뷰를 레이아웃 구성하는 부분은 핵심부분이 아니므로 생략 (전체 코드는 해당 포스팅 가장 하단에 존재)
class ViewController: UIViewController {
private let scrollView = UIScrollView()
private let contentView = UIView()
private let textField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupViews()
setupConstraints()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
private func setupViews() {
// ..
}
private func setupConstraints() {
// ..
}
- 키보드가 등장할 때 (willShow) 키보드의 height를 구해서 피팅해주는 코드
override func viewDidLoad() {
super.viewDidLoad()
...
setupKeyboardObservers()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
private func setupKeyboardObservers() {
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow(_:)),
name: UIResponder.keyboardWillShowNotification,
object: nil
)
}
@objc private func keyboardWillShow(_ notification: Notification) {
guard
let userInfo = notification.userInfo,
let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
else { return }
fitScrollingMinDistance(keyboardHeight: keyboardFrame.height)
}
private func fitScrollingMinDistance(keyboardHeight: CGFloat) {
// TODO: 핵심코드 구현
}
- fitScrollingMinDistance에서 구현
- 텍스트필드 하단과 키보드 상단과의 거리를 구하기
- 텍스트필드 하단은 textField.frame.maxY로 구하면 scrollView 원점 기준으로 그려지기 때문에 contentSize 영향을 받으므로 window기준인 상대좌표를 구해야함
- 키보드 상단의 y좌표는 디바이스 전체 height에서 키보드의 height를 뺀 값
- convert를 통해 상대좌표 구하는 개념은 이전 포스팅 글 참고
- 텍스트필드 하단과 키보드 상단과의 거리를 구하기
private func fitScrollingMinDistance(keyboardHeight: CGFloat) {
let superView = view.window ?? scrollView
let textFieldBottomY = textField.convert(textField.bounds, to: superView).maxY
let visibleAreaHeight = superView.frame.height - keyboardHeight
}
- 이제 이 값을 사용하여 스크롤을 얼마나 해야하는지 offsetY를 구하고, 이 offsetY값이 0보다 큰 경우가 스크롤이 필요한 경우이며 이 경우만 스크롤 처리
private func fitScrollingMinDistance(keyboardHeight: CGFloat) {
let superView = view.window ?? scrollView
let textFieldBottomY = textField.convert(textField.bounds, to: superView).maxY
let visibleAreaHeight = superView.frame.height - keyboardHeight
let minDistance = 50.0
let offsetY = textFieldBottomY + minDistance - visibleAreaHeight
guard offsetY > 0 else { return }
let currentContentOffset = scrollView.contentOffset
scrollView.setContentOffset(
CGPoint(x: currentContentOffset.x, y: currentContentOffset.y + offsetY),
animated: true
)
scrollView.layoutIfNeeded()
}
완성)
전체 코드)
import UIKit
class ViewController: UIViewController {
private let scrollView = UIScrollView()
private let contentView = UIView()
private let textField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupViews()
setupConstraints()
setupKeyboardObservers()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
private func setupViews() {
scrollView.backgroundColor = .lightGray
view.addSubview(scrollView)
contentView.backgroundColor = .white
scrollView.addSubview(contentView)
textField.placeholder = "Enter text"
textField.borderStyle = .roundedRect
textField.backgroundColor = .white
contentView.addSubview(textField)
}
private func setupConstraints() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
contentView.heightAnchor.constraint(equalToConstant: 1000)
])
NSLayoutConstraint.activate([
textField.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
textField.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
textField.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 500),
textField.heightAnchor.constraint(equalToConstant: 40)
])
}
private func setupKeyboardObservers() {
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow(_:)),
name: UIResponder.keyboardWillShowNotification,
object: nil
)
}
@objc private func keyboardWillShow(_ notification: Notification) {
guard
let userInfo = notification.userInfo,
let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
else { return }
fitScrollingMinDistance(keyboardHeight: keyboardFrame.height)
}
private func fitScrollingMinDistance(keyboardHeight: CGFloat) {
let superView = view.window ?? scrollView
let textFieldBottomY = textField.convert(textField.bounds, to: superView).maxY
let visibleAreaHeight = superView.frame.height - keyboardHeight
let minDistance = 50.0
let offsetY = textFieldBottomY + minDistance - visibleAreaHeight
guard offsetY > 0 else { return }
let currentContentOffset = scrollView.contentOffset
scrollView.setContentOffset(
CGPoint(x: currentContentOffset.x, y: currentContentOffset.y + offsetY),
animated: true
)
scrollView.layoutIfNeeded()
}
}
'iOS 응용 (swift)' 카테고리의 다른 글
[iOS - swift] 상대좌표 헷갈리기 쉬운 개념 convert(_:to:), convert(_:from:) (#좌표변환) (0) | 2025.01.07 |
---|---|
[iOS - SwiftUI] 뷰 속성 순서의 중요성 (SwiftUI 뷰 구현 중 놓치는 것) (0) | 2024.12.12 |
[iOS - SwiftUI] 터치 이벤트 받는 방법(contentShape) (1) | 2024.12.10 |
[iOS - SwiftUI] VStack, HStack을 사용할 때 주의할 점 (Stack 패딩, Stack 사이즈 고정) (3) | 2024.12.05 |
[iOS - swift] @retroactive 개념 (Swift6, Xcode16) (0) | 2024.12.02 |
Comments