I have checkout link which you have added in question. Blaaahhhh, very irritating due to some syntax has been changed. Anyways, I'm not going to explain whole tutorial that you already have done.
I have took reference from here: https://stackoverflow.com/a/56721268/6144643
Update LabelTextField
code as follows.
struct LabelTextField: View {
var label: String = ""
var placeHolder: String = ""
var tag: Int? = nil
var kGuardian: KeyboardGuardian
@State var textField: String = ""
var body: some View {
VStack(alignment: .leading) {
Text(label)
.font(.headline)
TextField(placeHolder, text: $textField, onEditingChanged: {
if $0 { self.kGuardian.showField = self.tag! }
})
.padding(.all)
.background(Color(red: 239.0/255.0, green: 243.0/255.0, blue: 244.0/255.0))
.cornerRadius(5.0)
}
.padding()
.listRowInsets(EdgeInsets())
}
}
Update code in ContentView
to initialise LabelTextField
as follow:
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 5)
var body: some View {
NavigationView {
List {
VStack(alignment: .leading) {
LabelTextField(label: "NAME", placeHolder: "Fill in the restaurant name", tag: 0, kGuardian: kGuardian, textField: "")
.background(GeometryGetter(rect: $kGuardian.rects[0]).foregroundColor(.clear))
LabelTextField(label: "TYPE", placeHolder: "Fill in the restaurant type", tag: 1, kGuardian: kGuardian, textField: "")
.background(GeometryGetter(rect: $kGuardian.rects[1]).foregroundColor(.clear))
LabelTextField(label: "ADDRESS", placeHolder: "Fill in the restaurant address", tag: 2, kGuardian: kGuardian, textField: "")
.background(GeometryGetter(rect: $kGuardian.rects[2]).foregroundColor(.clear))
LabelTextField(label: "PHONE", placeHolder: "Fill in the restaurant phone", tag: 3, kGuardian: kGuardian, textField: "")
.background(GeometryGetter(rect: $kGuardian.rects[3]).foregroundColor(.clear))
LabelTextField(label: "DESCRIPTION", placeHolder: "Fill in the restaurant description", tag: 4, kGuardian: kGuardian, textField: "")
.background(GeometryGetter(rect: $kGuardian.rects[4]).foregroundColor(.clear))
RoundedButton().padding(.top, 20)
}
.padding(.top, 20)
.listRowInsets(EdgeInsets())
.offset(y: kGuardian.slide).animation(Animation.linear(duration: 0.3))
}
.navigationBarTitle(Text("New Restaurant"), displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
}, label: {
Text("Cancel")
})
)
}
}
}
struct RoundedButton: View {
var body: some View {
Button(action: {}) {
HStack {
Spacer()
Text("Save")
.font(.headline)
.foregroundColor(.white)
Spacer()
}
}
.padding(.vertical, 10.0)
.background(Color.red)
.cornerRadius(4.0)
.padding(.horizontal, 50)
}
}
Add following code which are view that absorbs the size and position of its parent view.
struct GeometryGetter: View {
@Binding var rect: CGRect
var body: some View {
GeometryReader { geometry in
Group { () -> ShapeView<Rectangle, Color> in
DispatchQueue.main.async {
self.rect = geometry.frame(in: .global)
}
return Rectangle().fill(Color.clear) as! ShapeView<Rectangle, Color>
}
}
}
}
Then add following code for keyboard hide/show notification.
final class KeyboardGuardian: ObservableObject {
let objectWillChange = PassthroughSubject<Void, Never>()
public var rects: Array<CGRect>
public var keyboardRect: CGRect = CGRect()
// keyboardWillShow notification may be posted repeatedly,
// this flag makes sure we only act once per keyboard appearance
public var keyboardIsHidden = true
public var slide: CGFloat = 0 {
didSet {
objectWillChange.send()
}
}
public var showField: Int = 0 {
didSet {
updateSlide()
}
}
init(textFieldCount: Int) {
self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)
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)
}
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
print("tfRect", tfRect, "\nself.showField", self.showField)
if diff > 0 {
slide += diff
} else {
slide += min(diff, 0)
}
}
}
}