รหัสอัปเดตสำหรับ 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() }
}
เรขาคณิต
นี่คือมุมมองที่ดูดซับขนาดและตำแหน่งของมุมมองระดับบนสุด เพื่อให้บรรลุเป้าหมายนั้นเรียกว่าภายในตัวปรับแต่ง. 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)
}
}
}
}