CopyPastor

Detecting plagiarism made easy.

Score: 1; Reported for: Exact paragraph match Open both answers

Possible Plagiarism

Plagiarized on 2022-01-08
by PipEvangelist

Original Post

Original - Posted on 2019-10-04
by Michael Neas



            
Present in both answers; Present only in the new answer; Present only in the old answer;

# Works for iOS 15 with Swift 5.2 **External Package Required: [Introspect](https://github.com/siteline/SwiftUI-Introspect)**
I figured this out after sifting through multiple SO answers. The main idea is from this [SO answer](https://stackoverflow.com/a/68338066/4784433), but in his code, he used something like `Publishers` that just doesn't work on my end. Then, I figured out that he probably meant a keyboard-height observer that conforms to `Publisher` protocol.
## KeyboardResponder (to get and broadcast keyboard height) Not my code. All credit to to this [SO answer](https://stackoverflow.com/a/58242249/4784433): ```swift import SwiftUI
final class KeyboardResponder: ObservableObject { private var notificationCenter: NotificationCenter @Published private(set) var currentHeight: CGFloat = 0
init(center: NotificationCenter = .default) { notificationCenter = center notificationCenter.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) notificationCenter.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil) }
deinit { notificationCenter.removeObserver(self) }
@objc func keyBoardWillShow(notification: Notification) { if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { currentHeight = keyboardSize.height } }
@objc func keyBoardWillHide(notification: Notification) { currentHeight = 0 } } ```
## View Then, in my view struct, I use `introspectScrollView` to get access to `UIScrollView`, which would allow me to modify the content offsets based on data received from the `KeyboardResponder` class.
```swift import Introspect import SwiftUI
struct ContentView: View { @ObservedObject var keyboard = KeyboardResponder() @State private var keyboardHeight: CGFloat = 0 @State private var scrollView: UIScrollView? = nil var body: some View { VStack{ ScrollView { // ... }.introspectScrollView {scrollView = $0} YourTextField(...) } .onReceive(keyboard.$currentHeight) { height in // I use a conditional unwrap because in my app, the Scrollview above // is conditional depending on whether there are messeges fetched // from the server, which means the scrollView will be nil initially if let _ = scrollView { // I found out that the ScrollView content will reset their offsets // if I start typing in my TextField. So, I only want to update offsets // when there's no user inputs if TextInYourTextField == "" { if height > 0 { self.scrollView!.setContentOffset(CGPoint(x: 0, y: self.scrollView!.contentOffset.y + height), animated: true) } else { // For my app, I don't need the following but maybe helfpful for your situation //self.scrollView!.contentOffset.y = max(self.scrollView!.contentOffset.y - keyboardHeight, 0) } keyboardHeight = height } } } } } ```
The `.onReceive()` is applied to the `VStack`, NOT on the `ScrollView`.
To build off of @rraphael 's solution, I converted it to be usable by today's xcode11 swiftUI support.
``` import SwiftUI
final class KeyboardResponder: ObservableObject { private var notificationCenter: NotificationCenter @Published private(set) var currentHeight: CGFloat = 0
init(center: NotificationCenter = .default) { notificationCenter = center notificationCenter.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) notificationCenter.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil) }
deinit { notificationCenter.removeObserver(self) }
@objc func keyBoardWillShow(notification: Notification) { if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { currentHeight = keyboardSize.height } }
@objc func keyBoardWillHide(notification: Notification) { currentHeight = 0 } } ```
Usage:
``` struct ContentView: View { @ObservedObject private var keyboard = KeyboardResponder() @State private var textFieldInput: String = "" var body: some View { VStack { HStack { TextField("uMessage", text: $textFieldInput) } }.padding() .padding(.bottom, keyboard.currentHeight) .edgesIgnoringSafeArea(.bottom) .animation(.easeOut(duration: 0.16)) } } ```
The published `currentHeight` will trigger a UI re-render and move your TextField up when the keyboard shows, and back down when dismissed. However I didn't use a ScrollView.

        
Present in both answers; Present only in the new answer; Present only in the old answer;