Skip to content

Commit

Permalink
Add ignoresKeyboard option (#18)
Browse files Browse the repository at this point in the history
Co-authored-by: Muukii <[email protected]>
  • Loading branch information
takumatt and muukii authored Nov 21, 2024
1 parent ad41d02 commit 975f256
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 1 deletion.
79 changes: 78 additions & 1 deletion Development/Development/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@
//

import SwiftUI
import SwiftUIHosting

struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink("Content") {
BookSizing()
BookSizing()
}
NavigationLink("Keyboard Avoidance ignores") {
KeyboardAvoidanceViewControllerRepresentable(ignoresKeyboard: true)
.edgesIgnoringSafeArea(.all)
}

NavigationLink("Keyboard Avoidance not ignores") {
KeyboardAvoidanceViewControllerRepresentable(ignoresKeyboard: false)
.edgesIgnoringSafeArea(.all)
}
}
}
Expand All @@ -25,3 +35,70 @@ struct ContentView_Previews: PreviewProvider {
}
}

struct KeyboardAvoidanceViewControllerRepresentable: UIViewControllerRepresentable {

let ignoresKeyboard: Bool

init(ignoresKeyboard: Bool) {
self.ignoresKeyboard = ignoresKeyboard
}

func makeUIViewController(context: Context) -> some UIViewController {
KeyboardAvoidanceViewController(ignoresKeyboard: ignoresKeyboard)
}

func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {

}

}

final class KeyboardAvoidanceViewController: UIViewController, UITextFieldDelegate {

let ignoresKeyboard: Bool

init(ignoresKeyboard: Bool) {
self.ignoresKeyboard = ignoresKeyboard
super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
fatalError()
}

override func viewDidLoad() {
super.viewDidLoad()

let hostingView = SwiftUIHostingView(configuration: .init(ignoresKeyboard: ignoresKeyboard)) {
Text("Hello")
}

view.addSubview(hostingView)
hostingView.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
hostingView.rightAnchor.constraint(equalTo: view.rightAnchor),
hostingView.bottomAnchor
.constraint(equalTo: view.bottomAnchor, constant: -200),
hostingView.leftAnchor.constraint(equalTo: view.leftAnchor),
])

let textField = UITextField()
textField.borderStyle = .roundedRect
textField.delegate = self

textField.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(textField)

NSLayoutConstraint.activate([
textField.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}

}
28 changes: 28 additions & 0 deletions Sources/SwiftUIHosting/HostingController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ final class HostingController<Content: View>: UIHostingController<Content> {
init(
accessibilityIdentifier: String? = nil,
disableSafeArea: Bool,
ignoresKeyboard: Bool,
rootView: Content
) {

Expand All @@ -20,6 +21,33 @@ final class HostingController<Content: View>: UIHostingController<Content> {
// waiting for iOS 16.4 as minimum deployment target
_disableSafeArea = disableSafeArea

// https://steipete.com/posts/disabling-keyboard-avoidance-in-swiftui-uihostingcontroller/
if ignoresKeyboard {
guard let viewClass = object_getClass(view) else { return }

let viewSubclassName = String(cString: class_getName(viewClass)).appending("_IgnoresKeyboard")
if let viewSubclass = NSClassFromString(viewSubclassName) {
object_setClass(view, viewSubclass)
}
else {
guard let viewClassNameUtf8 = (viewSubclassName as NSString).utf8String else { return }
guard let viewSubclass = objc_allocateClassPair(viewClass, viewClassNameUtf8, 0) else { return }

if let method = class_getInstanceMethod(viewClass, NSSelectorFromString("keyboardWillShowWithNotification:")) {
let keyboardWillShow: @convention(block) (AnyObject, AnyObject) -> Void = { _, _ in
if ignoresKeyboard {

} else {

}
}
class_addMethod(viewSubclass, NSSelectorFromString("keyboardWillShowWithNotification:"),
imp_implementationWithBlock(keyboardWillShow), method_getTypeEncoding(method))
}
objc_registerClassPair(viewSubclass)
object_setClass(view, viewSubclass)
}
}
}

@MainActor required dynamic init?(coder aDecoder: NSCoder) {
Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftUIHosting/SwiftUIHostingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ open class SwiftUIHostingView<Content: View>: UIView {
self.hostingController = HostingController(
accessibilityIdentifier: _typeName(Content.self),
disableSafeArea: configuration.disableSafeArea,
ignoresKeyboard: configuration.ignoresKeyboard,
rootView: usingContent
)

#else

self.hostingController = HostingController(
disableSafeArea: configuration.disableSafeArea,
ignoresKeyboard: configuration.ignoresKeyboard,
rootView: usingContent
)

Expand Down Expand Up @@ -231,18 +233,22 @@ public struct SwiftUIHostingConfiguration {
*/
public var disableSafeArea: Bool

public var ignoresKeyboard: Bool

public var sizeMeasureMode: SwiftUIHostingSizeMeasureMode

public var baseModifier: BaseModifier

public init(
registersAsChildViewController: Bool = true,
disableSafeArea: Bool = true,
ignoresKeyboard: Bool = false,
sizeMeasureMode: SwiftUIHostingSizeMeasureMode = .systemSizeThatFits,
baseModifier: BaseModifier = .shared
) {
self.registersAsChildViewController = registersAsChildViewController
self.disableSafeArea = disableSafeArea
self.ignoresKeyboard = ignoresKeyboard
self.sizeMeasureMode = sizeMeasureMode
self.baseModifier = baseModifier
}
Expand Down

0 comments on commit 975f256

Please sign in to comment.