Skip to content

Instantly share code, notes, and snippets.

@scottmatthewman
Last active April 19, 2024 12:56
Show Gist options
  • Save scottmatthewman/722987c9ad40f852e2b6a185f390f88d to your computer and use it in GitHub Desktop.
Save scottmatthewman/722987c9ad40f852e2b6a185f390f88d to your computer and use it in GitHub Desktop.
An example of using Combine to automatically adapt a SwiftUI scrollable view to accommodate an iOS onscreen keyboard
import SwiftUI
import Combine
struct AdaptsToSoftwareKeyboard: ViewModifier {
@State var currentHeight: CGFloat = 0
func body(content: Content) -> some View {
content
.padding(.bottom, currentHeight)
.edgesIgnoringSafeArea(.bottom)
.onAppear(perform: subscribeToKeyboardEvents)
}
private func subscribeToKeyboardEvents() {
NotificationCenter.Publisher(
center: NotificationCenter.default,
name: UIResponder.keyboardWillShowNotification
).compactMap { notification in
notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect
}.map { rect in
rect.height
}.subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))
NotificationCenter.Publisher(
center: NotificationCenter.default,
name: UIResponder.keyboardWillHideNotification
).compactMap { notification in
CGFloat.zero
}.subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))
}
}
import SwiftUI
struct KeyboardAwareScrollableView : View {
@ObjectBinding var venue: SomeDataModel
var body: some View {
// Apply to any view with an instrinsic scroll view – ScrollView, Form, List, etc
Form {
Section {
TextField($venue.name, placeholder: Text("Venue Name"))
}
Section(header: Text("Address")) {
TextField($venue.street, placeholder: Text("Street"))
TextField($venue.city, placeholder: Text("City"))
TextField($venue.country, placeholder: Text("Country"))
TextField($venue.postalCode, placeholder: Text("Postcode/ZIP"))
}
// etc.
}
.navigationBarTitle(Text("New venue"))
.modifier(AdaptsToSoftwareKeyboard()) // <-- apply the modifier here
}
}
@ethanyuwang
Copy link

How do you make it scroll a bit higher? I tried this extra padding method but have a chunk of white space instead:

.padding(.bottom, currentHeight == 0 ? 0 : currentHeight + extraPadding)

Simulator Screen Shot - iPhone 11 Pro - 2020-08-31 at 22 31 28

@damirstuhec
Copy link

@ntornado
Copy link

ntornado commented Sep 4, 2020

@LukaszDziwosz
Copy link

LukaszDziwosz commented Nov 11, 2021

It doesn't work for me unfortunately. I only got ScrollView with 10 textfields. I think scrollview don't respect padding in Xcode 12.5.1

@santu1990
Copy link

Nice :)

@sskjames
Copy link

Will this work for TextEditor?

@kiddden
Copy link

kiddden commented Sep 11, 2022

@ethanyuwang did you find a solution for your issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment