⌨️A Combine-based way to observe and adjust for Keyboard notifications in SwiftUI

Overview

⌨️ Keyboard Observing

A Combine-based solution for observing and avoiding the keyboard in SwiftUI.

Swift Support Platform CocoaPods Compatible SwiftPM Compatible

Table of Contents

About

This package give you the ability to observe changes to keyboard state using the Keyboard ObservableObject type.

It also provides a KeyboardObservingView that adjusts its content to avoid the keyboard, and a .keyboardObserving() ViewModifier that adjusts the modified view to avoid the keyboard.

Demo

Requirements

  • iOS 13.0+
  • Xcode 11+
  • Swift 5.1+

Installation

This package can be installed using CocoaPods or Swift Package Manager.

CocoaPods

Add the following line to your Podfile:

pod 'KeyboardObserving'

For more information about how to get started with CocoaPods, check out the CocoaPods website.

Swift Package Manager

Add the following to your Package.swift file:

dependencies: [
    .package(
        url: "https://github.com/nickffox/KeyboardObserving.git", 
        .branch:("master")
    )
]

If you're using SPM through Xcode:

  1. Go to File > Swift Packages > Add Package Dependency
  2. Enter https://github.com/nickffox/KeyboardObserving
  3. Select the branch option, and type "master"

For more information about how to get started with the Swift Package Manager, check out the Official SPM website or the SPM project on GitHub.

Usage

Using the KeyboardObserving ViewModifier

Add the .keyboardObserving() ViewModifier to your custom SwiftUI view.

import KeyboardObserving

struct YourView: View {

  var body: some View {
    VStack {
      // Your Content Here
    }
    .keyboardObserving()
  }
}

Using Keyboard and KeyboardObservingView

1. Add a Keyboard to your environment

In your SceneDelegate.swift file, add a Keyboard property, and add it to your scene's environment.

import KeyboardObserving

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

  var window: UIWindow?

  // A Keyboard that will be added to the environment.
  var keyboard = Keyboard()


  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

    // Use a UIHostingController as window root view controller
    if let windowScene = scene as? UIWindowScene {
      let window = UIWindow(windowScene: windowScene)
      window.rootViewController = UIHostingController(
        rootView: YourRootView()
          // Adds the keyboard to the environment
          .environmentObject(keyboard)
      )
      self.window = window
      window.makeKeyAndVisible()
    }
  }
}
2. Create your View

Add your view's content inside of a KeyboardObservingView .

import KeyboardObserving

struct YourView: View {

  var body: some View {
    KeyboardObservingView {
      // Your content goes here!
    }
  }
}
Comments
  • Replaced implicit animation modifiers with explicit animation ('withA…

    Replaced implicit animation modifiers with explicit animation ('withA…

    Replaced implicit animation modifiers with explicit animation ('withAnimation'), in order to animate all the affected views returned in the content view, thus preventing non-keyboard animation to stuck. (Attached sample project) KeyboardObservingSample.zip

    opened by omroz 5
  • Adds flexible offset parameter

    Adds flexible offset parameter

    Hi @nickffox, thank you for this project. 🙂 Your solution is so simple and elegant! I need a bit more flexibility and added an offset variable. What do you think about it?

    opened by JulianKahnert 5
  • How to manually show/dismiss the keyboard?

    How to manually show/dismiss the keyboard?

    I found a way to hide the keyboard through the window hierarchy:

    extension View {
        func endEditing(_ force: Bool) {
            UIApplication.shared.windows.forEach { $0.endEditing(force)}
        }
    }
    

    But this is clearly not the best solution. I have not looked at all the code, but it will be sufficient to make this initializer public:

    //Keyboard.swift
        public init(animationDuration: TimeInterval, height: CGFloat) {
          self.animationDuration = animationDuration
          self.height = height
        }
    
        var body: some View {
            KeyboardObservingView {
                NavigationView {
                }
                .onTapGesture {
                    self.keyboard.state = Keyboard.State(animationDuration: 0,25, height: 0)
                }
           }
       }
    
    opened by SeRG1k17 2
  • Hiding view modifier with custom transitions

    Hiding view modifier with custom transitions

    Hello,

    I was experimenting with your library and found one use-case it currently doesn't solve.

    When you want some view to react on keyboard change with custom transition, you cannot currently do it. I iterated on the solution by @jaywardell, which always animated opacity. And I reimplemented it using view modifier.

    Here is a typical use-case. I want to move some view out of the screen when keyboard appears:

    recording

    How to use it:

    Image(systemName: "app.badge")
        .hideOnKeyboard(transition: .offset(x: 0, y: -300))
    

    Let me know what you think about the solution.

    opened by mkj-is 2
  • Add podspec to enable Cocoapods installs

    Add podspec to enable Cocoapods installs

    Fixes https://github.com/nickffox/KeyboardObserving/issues/5

    $ pod lib lint --no-clean
    
     -> KeyboardObserving (0.2.0)
        - NOTE  | xcodebuild:  note: Using new build system
        - NOTE  | [iOS] xcodebuild:  note: Planning build
        - NOTE  | [iOS] xcodebuild:  note: Constructing build description
        - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'KeyboardObserving' from project 'Pods')
        - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'Pods-App' from project 'Pods')
        - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'App' from project 'App')
        - NOTE  | [iOS] xcodebuild:  warning: Skipping code signing because the target does not have an Info.plist file and one is not being generated automatically. (in target 'App' from project 'App')
    
    Pods workspace available at `/var/folders/hr/v4vtphl130zczzkbpdkbs7qm0000gn/T/CocoaPods-Lint-20191114-20444-soqu5a-KeyboardObserving/App.xcworkspace` for inspection.
    
    KeyboardObserving passed validation.
    
    opened by ldiqual 0
  • In Mac catalyst apps, KeyboardObservingView was causing stuttering behavior during live resize

    In Mac catalyst apps, KeyboardObservingView was causing stuttering behavior during live resize

    KeyboardObservingView was causing stuttering behavior during live resize in mac catalyst

    This could cause problems in cross-platform project (like mine) Since we don't need to observe the keyboard in mac anyway, we simply don't send back the modifications when in mac catalyst

    opened by jaywardell 0
  • Adds ViewModifier

    Adds ViewModifier

    • Simplified KeyboardObservingView to ignore bottom safe area, and simplified keyboard height calculation for consistency.
    • Added KeyboardObserving ViewModifier, and convenience method keyboardObserving on View.
    opened by nickffox 0
  • [Alternative method of modifying views] Switched from modifying frame to using an offset

    [Alternative method of modifying views] Switched from modifying frame to using an offset

    Thanks for creating this Nick. I had a use case which required a slight modification that I thought might be useful for others.

    Let's say we have this:

    struct TestView: View {
        
        @State var text: String = ""
        
        var body: some View {
            VStack(spacing: 0) {
                Color.blue.frame(height: 300)
                
                Color.red
                
                TextField("Type something", text: $text)
                    .frame(height: 100)
                    .foregroundColor(Color.white)
                    .background(Color.black)
            }
            .keyboardObserving()
        }
    }
    

    Using the current KeyboardObserving, the result looks like this: before

    You can see it modifies the relative sizes of Blue and Red since Blue is constrained while Red is not.

    When I wrote my own keyboard avoiders before SwiftUI, I found messing with the frames sometimes gave hard to debug results so I had always preferred to simply use a transformation on the underlying layer and translate everything up.

    This gives the following result:

    after

    It may not be what your extension intends but thought it was a nice option to have.

    opened by ivanmkc 0
  • Added sample project and return Keyboard from the KeyboardObservingView

    Added sample project and return Keyboard from the KeyboardObservingView

    • Added empty Example to the library.
    • It will be useful if KeyboardObservingView will return Keyboard object as a parameter to ViewBuilder:
    KeyboardObservingView { keyboard in 
    //
    }
    

    I found the issue, when you adding @EnvironmentObject var keyboard: Keyboard to the View. This leads to the fact that the field values are cleared after changing the field on this view or on the next in the nav stack.

    • @nickffox What do you think, about using Environment?:
    struct KeyboardKey: EnvironmentKey {
        static let defaultValue: Keyboard = Keyboard()
    }
    
    extension EnvironmentValues {
        var keyboard: Keyboard {
            get {
                return self[KeyboardKey.self]
            }
            set {
                self[KeyboardKey.self] = newValue
            }
        }
    }
    
    opened by SeRG1k17 2
Owner
Nick Fox
Nick Fox
Best way to dismiss Keyboard in a View Controller iOS (Swift)

Best way to dismiss Keyboard in a View Controller iOS (Swift) First way: Implement UITextFieldDelegate’s textFieldShouldReturn method and dismiss curr

null 0 Dec 18, 2021
A drop-in universal solution for moving text fields out of the way of the keyboard in iOS

TPKeyboardAvoiding A drop-in universal solution for moving text fields out of the way of the keyboard in iOS. Introduction There are a hundred and one

Michael Tyson 5.8k Dec 26, 2022
SwiftUIKeyPress - a package to make up for the lack of keyboard input in SwiftUI

SwiftUIKeyPress - a package to make up for the lack of keyboard input in SwiftUI

Underthestars-zhy 8 Oct 27, 2022
Codeless drop-in universal library allows to prevent issues of keyboard sliding up and cover UITextField/UITextView. Neither need to write any code nor any setup required and much more.

IQKeyboardManager While developing iOS apps, we often run into issues where the iPhone keyboard slides up and covers the UITextField/UITextView. IQKey

Mohd Iftekhar Qurashi 15.9k Jan 8, 2023
KeyboardKit is a Swift library that helps you create custom keyboard extensions for iOS and ipadOS.

KeyboardKit is a Swift library that helps you create custom keyboard extensions for iOS and ipadOS.

KeyboardKit 900 Jan 9, 2023
A simple keyboard to use with numbers and, optionally, a decimal point.

MMNumberKeyboard A simple keyboard to use with numbers and, optionally, a decimal point. Installation From CocoaPods CocoaPods is a dependency manager

Matías Martínez 957 Nov 17, 2022
Prevent keyboard from covering UITextField/UITextView, includes Swift and Objective-C APIs

Prevent keyboard from covering UITextField/UITextView with only one line of code, includes Swift and Objective-C APIs.

LiuChang 8 Oct 24, 2022
IHKeyboardAvoiding is an elegant solution for keeping any UIView visible when the keyboard is being shown - no UIScrollView required!

IHKeyboardAvoiding An elegant solution for keeping any UIView visible when the keyboard is being shown Requirements IHKeyboardAvoiding Version Objecti

Idle Hands Apps 1.4k Dec 14, 2022
Codeless manager to hide keyboard by tapping on views for iOS written in Swift

KeyboardHideManager KeyboardHideManager - codeless manager to hide keyboard by tapping on views for iOS written in Swift. Structure Features Requireme

Bondar Yaroslav 55 Oct 19, 2022
⌨️ Add user-customizable global keyboard shortcuts to your macOS app in minutes

This package lets you add support for user-customizable global keyboard shortcuts to your macOS app in minutes. It's fully sandbox and Mac App Store c

Sindre Sorhus 1.1k Dec 29, 2022
Swift UIKit keyboard manager for iOS apps.

Typist Typist is a small, drop-in Swift UIKit keyboard manager for iOS apps. It helps you manage keyboard's screen presence and behavior without notif

Toto Tvalavadze 1.1k Dec 10, 2022
Suppress mouse & keyboard events on MacOSX. Baby-proof my Mac!

Suppress mouse & keyboard events on MacOSX Catches all events (mouse, keyboard, everything), and either consumes them (locked state) or passes them th

Albert Zeyer 6 Oct 21, 2022
QMK Agent is a macOS menubar application which sends commands to a QMK enabled keyboard

QMKagent QMK Agent is a macOS menubar application which sends commands to a QMK enabled keyboard Features System volume indicator using top row (Esc t

Mike Killewald 4 Apr 24, 2022
Showing / dismissing keyboard animation in simple UIViewController category.

RSKKeyboardAnimationObserver Easy way to handle iOS keyboard showing/dismissing. Introduction Working with iOS keyboard demands a lot of duplicated co

Ruslan Skorb 45 Jun 9, 2022
Objective-C library for tracking keyboard in iOS apps.

NgKeyboardTracker Objective-c library for tracking keyboard in iOS apps. Adding to your project If you are using CocoaPods, add to your Podfile: pod '

Meiwin Fu 808 Nov 17, 2022
For less complicated keyboard event handling.

KeyboardObserver For less complicated keyboard event handling. Features Less complicated keyboard event handling. Do not use Notification , but event

Morita Naoki 163 May 24, 2022
KeyboardMan helps you to make keyboard animation.

KeyboardMan We may need keyboard infomation from keyboard notifications to do animation. However, the approach is complicated and easy to make mistake

null 353 Apr 19, 2022
Emoji Keyboard SDK (iOS)

Makemoji SDK Makemoji is a free emoji keyboard for mobile apps. By installing our keyboard SDK every user of your app will instantly have access to ne

Makemoji 100 Nov 3, 2022
A Chinese keyboard for iOS that helps Chinese language learners remember tones.

ToneBoard ToneBoard is a Chinese keyboard for iOS that requires you to enter the correct tones while typing simplified Chinese with Pinyin. It is avai

Kevin Bell 7 Sep 27, 2022