Xcode 베타 7 용 코드가 업데이트되었습니다.
이를 위해 패딩, ScrollViews 또는 목록이 필요하지 않습니다. 이 솔루션은 그들과도 잘 어울릴 것입니다. 여기에 두 가지 예가 포함되어 있습니다.
첫 번째 는 키보드가 나타나면 모든 textField를 위로 이동 합니다. 그러나 필요한 경우에만. 키보드가 텍스트 필드를 숨기지 않으면 움직이지 않습니다.
두 번째 예에서보기는 활성 텍스트 필드를 숨기지 않도록 충분히 이동합니다.
두 예제 모두 끝에있는 동일한 공통 코드 인 GeometryGetter 및 KeyboardGuardian을 사용합니다.
첫 번째 예 (모든 텍스트 필드 표시)
struct ContentView: View {
@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 1)
@State private var name = Array<String>.init(repeating: "", count: 3)
var body: some View {
VStack {
Group {
Text("Some filler text").font(.largeTitle)
Text("Some filler text").font(.largeTitle)
}
TextField("enter text #1", text: $name[0])
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("enter text #2", text: $name[1])
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("enter text #3", text: $name[2])
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[0]))
}.offset(y: kGuardian.slide).animation(.easeInOut(duration: 1.0))
}
}
두 번째 예 (활성 필드 만 표시)
struct ContentView: View {
@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 3)
@State private var name = Array<String>.init(repeating: "", count: 3)
var body: some View {
VStack {
Group {
Text("Some filler text").font(.largeTitle)
Text("Some filler text").font(.largeTitle)
}
TextField("text #1", text: $name[0], onEditingChanged: { if $0 { self.kGuardian.showField = 0 } })
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[0]))
TextField("text #2", text: $name[1], onEditingChanged: { if $0 { self.kGuardian.showField = 1 } })
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[1]))
TextField("text #3", text: $name[2], onEditingChanged: { if $0 { self.kGuardian.showField = 2 } })
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(GeometryGetter(rect: $kGuardian.rects[2]))
}.offset(y: kGuardian.slide).animation(.easeInOut(duration: 1.0))
}.onAppear { self.kGuardian.addObserver() }
.onDisappear { self.kGuardian.removeObserver() }
}
기하학 Getter
이것은 상위 뷰의 크기와 위치를 흡수하는 뷰입니다. 이를 달성하기 위해 .background 수정 자 내부에서 호출됩니다. 이것은 단순히 뷰의 배경을 장식하는 방법이 아니라 매우 강력한 수정 자입니다. .background (MyView ())에 뷰를 전달할 때 MyView는 수정 된 뷰를 부모로 가져옵니다. GeometryReader를 사용하면 뷰가 부모의 지오메트리를 알 수 있습니다.
예 : Text("hello").background(GeometryGetter(rect: $bounds))
텍스트보기의 크기와 위치 및 전역 좌표 공간을 사용하여 변수 경계를 채 웁니다.
struct GeometryGetter: View {
@Binding var rect: CGRect
var body: some View {
GeometryReader { geometry in
Group { () -> AnyView in
DispatchQueue.main.async {
self.rect = geometry.frame(in: .global)
}
return AnyView(Color.clear)
}
}
}
}
업데이트 DispatchQueue.main.async를 추가하여 렌더링되는 동안 뷰의 상태를 수정할 가능성을 방지했습니다. ***
KeyboardGuardian
KeyboardGuardian의 목적은 키보드 표시 / 숨기기 이벤트를 추적하고보기를 이동해야하는 공간의 양을 계산하는 것입니다.
업데이트 : 사용자가 한 필드에서 다른 필드로 탭할 때 슬라이드를 새로 고치도록 KeyboardGuardian을 수정했습니다 .
import SwiftUI
import Combine
final class KeyboardGuardian: ObservableObject {
public var rects: Array<CGRect>
public var keyboardRect: CGRect = CGRect()
public var keyboardIsHidden = true
@Published var slide: CGFloat = 0
var showField: Int = 0 {
didSet {
updateSlide()
}
}
init(textFieldCount: Int) {
self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)
}
func addObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardDidHide(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}
func removeObserver() {
NotificationCenter.default.removeObserver(self)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func keyBoardWillShow(notification: Notification) {
if keyboardIsHidden {
keyboardIsHidden = false
if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
keyboardRect = rect
updateSlide()
}
}
}
@objc func keyBoardDidHide(notification: Notification) {
keyboardIsHidden = true
updateSlide()
}
func updateSlide() {
if keyboardIsHidden {
slide = 0
} else {
let tfRect = self.rects[self.showField]
let diff = keyboardRect.minY - tfRect.maxY
if diff > 0 {
slide += diff
} else {
slide += min(diff, 0)
}
}
}
}