Swift UIKit keyboard manager for iOS apps.

Overview

Typist

Swift Version Platform CocoaPods Compatible Carthage compatible Accio supported Twitter

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


Usage

Declare what should happen on what event and start() listening to keyboard events. That's it.

let keyboard = Typist.shared // use `Typist()` whenever you can, see note on singleton usage below

func configureKeyboard() {

    keyboard
        .on(event: .didShow) { (options) in
            print("New Keyboard Frame is \(options.endFrame).")
        }
        .on(event: .didHide) { (options) in
            print("It took \(options.animationDuration) seconds to animate keyboard out.")
        }
        .start()

}

You must call start() for callbacks to be triggered. Calling stop() on instance will stop callbacks from triggering, but callbacks themselves won't be dismissed, thus you can resume event callbacks by calling start() again.

To remove all event callbacks, call clear().

Interactivity and inputAccessoryView

You can dismiss keyboard interactively when using Typist with UIScrollView instances.

let keyboard = Typist()

func configureKeyboard() {

    keyboard
        .toolbar(scrollView: tableView) // Enables interactive dismissal
        .on(event: .willChangeFrame) { (options) in
            // You are responsible animating inputAccessoryView
        }
        .on(event: .willHide)  { (options) in
            // Triggered when keyboard is dismissed non-interactively.
        }
        .start()

}

.on(event: .willChangeFrame, do: {...}) will update as frequently as keyboard frame changes due to UIScrollView scrolling. It is good practice to implement .willHide portion as well since keyboard might be dismissed non-interactively, for example, using resignFirstResponder().

Example from above is implemented in demo app.

On Singleton Usage

Usage of shared singleton, considered to be OK for convenient access to instance. However, it is strongly recommended to instantiate dedicated Typist() for each usage (in UIViewController, most likely). Do not use singleton when two or more objects using Typist.shared are presented on screen simultaneously, as it will cause one of the controllers to fail receiving keyboard events.

Event Callback Options

Every event callback has a parameter of Typist.KeyboardOptions type. It is an inert/immutable struct which carries all data that keyboard has at the event of happening:

  • belongsToCurrentAppBool that identifies whether the keyboard belongs to the current app. With multitasking on iPad, all visible apps are notified when the keyboard appears and disappears. The value is true for the app that caused the keyboard to appear and false for any other apps.
  • startFrameCGRect that identifies the start frame of the keyboard in screen coordinates. These coordinates do not take into account any rotation factors applied to the view’s contents as a result of interface orientation changes. Thus, you may need to convert the rectangle to view coordinates (using the convert(CGRect, from: UIView?) method) before using it.
  • endFrameCGRect that identifies the end frame of the keyboard in screen coordinates. These coordinates do not take into account any rotation factors applied to the view’s contents as a result of interface orientation changes. Thus, you may need to convert the rectangle to view coordinates (using the convert(CGRect, from: UIView?) method) before using it.
  • animationCurveUIView.AnimationCurve constant that defines how the keyboard will be animated onto or off the screen.
  • animationDurationDouble that identifies the duration of the animation in seconds.
  • animationOptionsUIView.AnimationOptions helper property that maps the animationCurve to its respective UIView.AnimationOptions value. Usefull when performming view animations using UIView.animate(....

Events

Following keyboard events are supported:

  • willShow
  • didShow
  • willHide
  • didHide
  • willChangeFrame
  • didChangeFrame – e.g. when keyboard is dynamically dismissed from scroll view interaction.

If you declare two closures on same event, only latter will be executed.


Installation

CocoaPods

You can use CocoaPods to install Typist by adding it to your Podfile:

platform :ios, '8.0'
use_frameworks!
pod 'Typist'

Import Typist wherever you plan to listen to keyboard events. Usually in your UIViewController subclasses.

import UIKit
import Typist

Carthage

Create a Cartfile that lists the framework and run carthage update. Follow the instructions to add $(SRCROOT)/Carthage/Build/iOS/Typist.framework to an iOS project.

github "totocaster/Typist"

Accio

Initialize your project with Accio using the init command.

Add the following to your Package.swift:

.package(url: "https://github.com/totocaster/Typist.git", .upToNextMajor(from: "1.4.2")),

Next, add Typist to your App targets dependencies like so:

.target(
    name: "App",
    dependencies: [
        "Typist",
    ]
),

Then run accio update.

Manually

Download and drop Typist.swift in your project.


My thanks to Jake Marsh for featuring Typist on Little Bites of Cocoa #282: Taming the Keyboard with Typist ⌨️ . It made my day.


License

Typist is released under the MIT license. See LICENSE for details.

Comments
  • How to use options.animationCurve?

    How to use options.animationCurve?

    I'm trying to setup a UIView animation to match the keyboard animation, including the animation curve. .animationCurve is available from Typist.KeyboardOptions, but I'm getting a type error. Any way around this?

    UIView.animate(withDuration: options.animationDuration, delay: 0, options: options.animationCurve, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)
    
    Cannot convert value of type 'UIViewAnimationCurve' to expected argument type 'UIViewAnimationOptions'
    
    opened by kgn 7
  • Added Input Accessory View Support

    Added Input Accessory View Support

    Added input accessory view support (#15) by adding a scrollView property to track panning. You also need to set the inputAccessoryView on the textField.

    Observes the input accessory view through the willChangeFrame and didChangeFrame observer.

    Demo has been updated to reflect the changes.

    // keyboard input accessory view support
    textField.inputAccessoryView = UIView(frame: toolbar.bounds)
    keyboard.scrollView = tableView
    
    // keyboard frame observer
    keyboard.on(event: .willChangeFrame) { [unowned self] options in
        let height = UIScreen.main.bounds.height - options.endFrame.origin.y
        self.bottom.constant = max(0, height - self.toolbar.bounds.height)
        UIView.animate(withDuration: 0) {
            self.tableView.contentInset.bottom = max(self.toolbar.bounds.height, height)
            self.tableView.scrollIndicatorInsets.bottom = max(self.toolbar.bounds.height, height)
            self.view.layoutIfNeeded()
        }
    }.start()
    

    Im also considering an alternative implementation like BABFrameObservingInputAccessoryView.

    opened by efremidze 5
  • SPM Doesn't work, please add 1.4.3 release

    SPM Doesn't work, please add 1.4.3 release

    Same issue as #35, the problem is that SPM reads Github releases and cannot find 1.4.3.

    Just add 1.4.3 release to fix it.

    Screenshot 2021-05-14 at 11 38 48

    It works here: https://github.com/tymofiidolenko/Typist/releases/tag/1.4.3

    I have XCode 12.5

    opened by timdolenko 4
  • Make it possible to use typist in multiple View controllers at the same time

    Make it possible to use typist in multiple View controllers at the same time

    I'm aware of the current limitations of using a singleton instance and start/stop methods to setup and remove listeners.

    I'm opening this issue to start conversation about how to best address this limitation so that multiple typist instances can be setup at the same time for example from a full screen view controller on the iPad and another modally present page view controller that is occupying just part of the screen (page modal view controller)

    Quickly thinking out loud I think it should be possible instead of using a singleton just instantiate and start typist in viewDidLoad and stop it in deinit...

    Any thoughts on this?

    Thanks Martin

    opened by mman 4
  • The singleton pattern is encouraged, but doesn't support multiple callbacks

    The singleton pattern is encouraged, but doesn't support multiple callbacks

    Since callbacks only stores one closure of each event type, multiple controllers that use Typist.shared will "fight" over who receives notifications.

    class ControllerOne: UIViewController {
      override func viewDidLoad() {
        Typist.shared.on(event: .willShow) { _ in print("will show from one") }
      }
    }
    
    class ControllerTwo: UIViewController {
      override func viewDidLoad() {
        Typist.shared.on(event: .willShow) { _ in print("will show from two") }
      }
    }
    

    If both of these controllers are loaded, only the second controller will get the notifications.

    Easy fix: remove the singleton, and have each controller retain its own Typist instance.

    opened by colinta 4
  • Silencing the warning

    Silencing the warning

    When there's no need to store the result of the last .on(:_,:_) function call, the warning is raised. Fixed that. Looks like in most cases this behaviour is more practical.

    opened by nikans 3
  • Add support for Swift Package Manager in Xcode 11

    Add support for Swift Package Manager in Xcode 11

    Could you please add support for SPM in Xcode 11? Currently Xcode gives the error 'has no Package.swift manifest for version 1.4.2' when adding the package to the Xcode project.

    opened by geertbeskers 2
  • ios 12 changes

    ios 12 changes

    Seems like lot of constants have changed, 'UIApplicationDidBecomeActive' has been renamed to 'UIApplication.didBecomeActiveNotification' 'kCAFillModeBoth' has been renamed to 'CAMediaTimingFillMode.both' 'UIApplicationDidBecomeActive' has been renamed to 'UIApplication.didBecomeActiveNotification'

    and a few more

    opened by sowri 2
  • Add support for SwiftPM based dependency managers

    Add support for SwiftPM based dependency managers

    This adds support for SwiftPM manifest based dependency managers. Specifically this adds support for installing via Accio but will probably also work with SwiftPM once it's integrated into Xcode.

    opened by Jeehut 1
  • Add UIView.AnimationOptions variable to KeyboardOptions struct

    Add UIView.AnimationOptions variable to KeyboardOptions struct

    In order to smoothly animate our views at par with iOS keyboard, we must useUIView.animate(withDuration:delay:options:animations:completion:) method which takes UIViewAnimationOptions as it's options argument value.

    Right now we must convert KeyboardOptions.animationCurve from UIView.AnimationCurve to UIView.AnimationOptions in order to call our animate function.

    To make our lives easier and our code cleaner, I've implemented a helper variable called animationOptions in Typist.KeyboardOptions struct, which transforms a given UIView.AnimationCurve to its respective UIView.AnimationOptions value.

    opened by Tylerian 1
Releases(1.4.0)
Owner
Toto Tvalavadze
I make iOS apps, design interfaces, and walk with a camera.
Toto Tvalavadze
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
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
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
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
Slidden is an open source, customizable, iOS 8 keyboard, written in Swift

Slidden is an open source, customizable, iOS 8 keyboard, written in Swift. iOS 8 brought us the ability to create fully customizable keyboards, but do

Daniel Brim 595 Jan 5, 2023
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
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
SwiftyKeyboard: a full customized numeric keyboard for iOS

SwiftyKeyboard Overview SwiftyKeyboard is an iOS customized enhanced keyboard. T

SwiftyKit 2 Jun 30, 2022
Emoji Keyboard for iOS

English | 中文 An easy to use Emoji keyboard for iOS. Has been rewritten with swift, the old Objective-C version on branch oc. Features Written in Swift

isaced 450 Dec 24, 2022
Interactive Keyboard Controller for Swift

Keynode Why Using UIScrollViewKeyboardDismissMode added in iOS7, interactive keyboard operation became possible. But, it only works on UIScrollView. K

Kyohei Ito 76 Sep 1, 2020
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 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
⌨️ 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
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
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