SwiftUI keyboard 이벤트 감지하기
앱 개발에 있어서 키보드 상태에 따라서 뷰의 다른 컴포넌트들의 높이가 조정되는 등 키보드와 관련해서는 꽤나 까다로움
UIKit을 사용한다면
- iOS 15 이상: keyboardLayoutGuide를 활용하여 레이아웃을 잡기
- iOS 14 이하: 키보드의 상태에 따라 키보드의 높이를 계산해서 뷰의 위치를 조정
view.keyboardLayoutGuide
SwiftUI 사용
- iOS 15 이상: @FocusState 활용
- iOS 14 이하: NotificationCenter와 Combine을 활용
샘플코드
키보드 상태를 읽을 수 있도록 아래 코드를 작성
protocol KeyboardReadable {
var keyboardPublisher: AnyPublisher<Bool, Never> { get }
}
extension KeyboardReadable {
var keyboardPublisher: AnyPublisher<Bool, Never> {
Publishers.Merge(
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { _ in true },
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in false }
)
.eraseToAnyPublisher()
}
}
위처럼 작성하고 아래처럼 뷰를 구현
import SwiftUI
import Combine
final class ContentViewModel: ObservableObject,
KeyboardReadable {
enum Action {
case shouldResignKeyboard
}
/// 검색어
@Published var searchText: String = ""
/// 키보드가 열려있는지 여부
@Published var isShowingKeyboard: Bool = false
init() {
bind()
}
private var cancellables = Set<AnyCancellable>()
private func bind() {
keyboardPublisher
.removeDuplicates()
.sink { [weak self] isShowing in
print("\(isShowing)")
guard let self else { return }
self.isShowingKeyboard = isShowing
}.store(in: &cancellables)
}
func send(action: Action) {
switch action {
case .shouldResignKeyboard:
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
to: nil, from: nil, for: nil)
}
}
}
struct ContentView: View {
@StateObject var viewModel = ContentViewModel()
var body: some View {
VStack {
Text(
viewModel.isShowingKeyboard
? "키보드가 올라와 있어요."
: "키보드가 내려간 상태에요."
)
TextField("검색어를 입력하세요.", text: $viewModel.searchText)
.autocorrectionDisabled()
.textFieldStyle(.roundedBorder)
Button {
viewModel.send(action: .shouldResignKeyboard)
} label: {
Text("키보드 강제로 내리는 버튼")
}
.buttonStyle(.bordered)
Text("Hello, world!")
}
.padding()
}
}
#Preview {
ContentView()
}
키보드 뿐만 아니라 SwiftUI는 뷰가 많이 쪼개지기 때문에 해당 형태를 살짝 변형하여 Delegate Pattern 처럼 변형해 해당 뷰에서 발생하는 이벤트를 다른 뷰로 전달할 수 있다.
해당 코드 동작 영상
'apple > SwiftUI, Combine' 카테고리의 다른 글
SwiftUI @FoucsState @FocusedValue @FocusedObject (0) | 2024.08.08 |
---|---|
[SwiftUI] NavigationLink 화살표 없애기 (0) | 2024.03.11 |
[SwiftUI] EqutableView (feat. POD) (0) | 2023.08.08 |
[iOS] NavigationSplitView (0) | 2023.08.05 |
Swift Combine Networking (0) | 2022.06.11 |