KeyboardKit is a Swift SDK that lets you create fully customizable keyboards with a few lines of code, using SwiftUI.
MIT License
Bot releases are visible (Hide)
This version adds the very first (and so far limited) support for SwiftUI
. Many new features are iOS 13-specific. However, due to a compilation bug, it has to be in a separate repo for now.
To add SwiftUI support to KeyboardKit, you must add KeyboardKitSwiftUI
together with KeyboardKit.
This version deprecates some action handling logic and adds new functions that doesn't rely on UIView
.
KeyboardInputViewController
has a new setupNextKeyboardButton(...)
which turns any UIButton
into a system-handled "next keyboard" button.
NextKeyboardUIButton
makes use of this new functionality, and sets itself up with a globe
icon.
PhotoImageService
and StandardPhotoImageService
can be used to save images to photos with a completion instead of a target and a selector.
KeyboardImageActions
makes it easy to create .image
actions from a set of image names.
KeyboardActionHandler
has a new open handle(_ gesture:on:view:)
which is already implemented in StandardKeyboardActionHandler
.
isKeyboardEnabled
can be used to check if certain keyboard extension is enabled or not.
The keyboardSettings
URL
extension helps you find the url to application settings.
The evened(for gridSize: Int)
[KeyboardAction]
extension appends enough .none
actions to evenly fit the grid size.
The saveToPhotos(completion:)
UIImage
ext. is a completion-based way to save images to photos.
There are some new views that can be used in SwiftUI-based apps and keyboard extensions:
KeyboardGrid
distributes actions evenly within a grid.
KeyboardGridRow
is used for each row in the grid.
KeyboardHostingController
can be used to wrap any View
in a keyboard extension.
KeyboardImageButton
view lets you show an .image
action or Image
in a Button
.
NextKeyboardButton
uses a globe
icon and works as a standard "next keyboard" button.
PersistedKeyboardSetting
is a new property wrapper for persisting settings in UserDefaults
.
Color.clearInteractable
can be used instead of .clear
to allow gestures to be detected.
Image.globe
returns the icon that is used for "next keyboard".
KeyboardInputViewController
setup(with:View)
sets up a KeyboardHostingController
.
View
withClearInteractableBackground()
can be used to make an entire view interactable.
Note that KeyboardKitSwiftUI
is a separate framework that you must import to get these features.
There are some new UIKit features and extensions:
NextKeyboardUIButton
sets itself up with a globe
icon and works as a standard "next keyboard" button.UIImage.globe
returns the icon that is used for "next keyboard".All UIKit-specific functionality is placed in the UIKit
folder. UIKit-based logic that can be used in SwiftUI is placed outside of this folder.
isInputAction
now includes .space
.isSystemAction
no longer includes .space
.UIColor.clearTappable
has been renamed to UIColor.clearInteractable
.KeyboardActionHandler
has deprecated the gesture-explicit handle functions.KeyboardActionHandler
has deprecated the view-explicit handle function in favor of an optional Any
sender variant.StandardKeyboardActionHandler
has deprecated a bunch of UIView
-explicit functions in favor of an optional Any
sender variant.This version fixes a bug, where moveCursorForward
moved the cursor incorrectly.
This version adds more autocomplete functionality:
AutocompleteToolbar
has a new convenience initializer that makes it even easier to setup autocomplete.AutocompleteToolbarLabel
is the default autocomplete item view and can be tapped to send text to the text document proxy.AutocompleteToolbarLabel
behaves like the native iOS autocomplete view and displays centered text until the text must scroll.The StandardKeyboardActionHandler
has new functionality:
animationButtonTap()
- can be overridden to change the default animation of tapped buttons.Deprecations:
AutocompleteBugFixTimer
and all timer-related logic has been deprecated.AutoCompleteSuggestionProvider
's provideAutocompleteSuggestions(for:completion:)
is deprecated and replaced with autocompleteSuggestions(for:completion:)
.StandardKeyboardActionHandler
's handleXXX(on:)
are now deprecated and replaced with handle(:on:view:)
.2.5.0 adds new features (like audio feedback), tweaks some behaviors and deprecates some logic:
New stuff:
KeyboardActionGesture
that will be used to streamline the action handling api:s.AudioFeedback
enum that describes various types of audio feedback.AudioFeedbackConfiguration
that lets you gather all configurations in one place.HapticFeedback.standardFeedback(for:)
function that replaces the old specific properties.HapticFeedbackConfiguration
that lets you gather all configurations in one place.StandardKeyboardActionHandler
init that uses this new configuration.StandardKeyboardActionHandler.triggerAudioFeedback(for:)
that can be used to trigger audio feedback.StandardKeyboardActionHandler.triggerHapticFeedback(for:on:)
that replaces the old gesture-specific ones.StandardKeyboardActionHandler.gestureAction(for:)
function that is used by the implementation. The old ones are still around.KeyboardType.images
case that is used by the demo.Changed behavior:
standardButtonShadow
Shadow
property that can be used to mimic the native button shadow.Deprecated stuff:
StandardKeyboardActionHandler.init(...)
is deprecated, use the new one.StandardKeyboardActionHandler.giveHapticFeedbackForLongPress(...)
is deprecated, use the new one.StandardKeyboardActionHandler.giveHapticFeedbackForRepeat(...)
is deprecated, use the new one.StandardKeyboardActionHandler.giveHapticFeedbackForTap(...)
is deprecated, use the new one.HapticFeedback.standardTapFeedback
and standardLongPressFeedback
have been replaced by the new function.The old handle
functions are still declared in the KeyboardActionHandler
protocol, but will be removed in the next major version.
This version adds autocomplete support, which includes an autocomplete suggestion provider protocol, a new toolbar and new extensions.
The new AutocompleteSuggestionProvider
protocol describes how to provide your keyboard with autocomplete suggestions. You can implement it in any way you like, e.g. to use a built-in suggestion database or by connecting to an external data source, using network requests. Note that the network option will be a lot slower and also require you to request full access from your users.
The new AutocompleteToolbar
is a toolbar that can display any results you receive from your suggestion provider (or any list of strings for that matter). Just trigger the provider anytíme the text changes and route the result to the toolbar. The toolbar can be populated with any kind of views. Have a look at the demo app for an example.
The new UITextDocumentProxy+CurrentWord
extension helps you get the word that is (most probably) being typed. You could use this when requesting autocomplete suggestions, if you only want to autocomplete the current word.
Besides these additions, there are a bunch of new extensions, like UITextDocumentProxy
deleteBackwards(times:)
, which lets you delete a certain number of characters. Have a look at the Extensions
namespace for a complete list.
There is also a new KeyboardShiftState
enum that you can use to keep track of which state your keyboard has, if any. This enum is extracted from demo app code that was provided by @arampak earlier this year.
IMPORTANT iOS has a bug that causes textWillChange
and textDidChange
to not be called when the user types, only when the cursor moves. This causes autocomplete problems, since the current word is not changing as the user types. Due to this, the input view controller must use an ugly hack to force the text document proxy to update. Have a look at the demo app to see how this is done.
This version adds more keyboard actions that don't exist in iOS, but that may serve a functional or semantical purpose in your apps:
command
custom(name:)
escape
function
option
tab
The new custom
action is a fallback that you can use if the existing action set is insufficient for your specific app.
I have added a RepeatingGestureRecognizer
and an extension that you can use to apply it as well. It has a custom initial delay as well as a custom repeat interval, that will let you tap and hold a button to repeat its action. In the next update, I will apply this to the backspace and arrow buttons.
Thanks to @arampak, the demo app now handles shift state and long press better, to make the overall experience much nicer and close to the native keyboard. The keyboard buttons also registers tap events over the entire button area, not just the button view.
This version solves some major bugs in the repeating gesture recognizer and makes some public
parts of the library open
.
The standard action handler now handles repeating actions for backspace. You can customize this in the same way as you customize tap and long press handling.
You can test the new repeating logic in the demo app.
This version makes a bunch of previously internal extensions public, since they are now covered by unit tests. It also adds a lot more unit tests to cover most parts of the library.
The default tap animation has been configured to allow user interaction, which reduces the frustrating tap lag that was present in 2.0.0. Sorry about that!
I have added a KeyboardToolbar
class, which you can use to create toolbars. It's super simple so far, and only creates a stack view to which you can any views you like.
This version adds a public shadow extension to the main library and shuffles classes and extensions around. It also restructures the example project to make it less cluttered.
I also noticed that the build number bump randomly bumps the build number incorrectly, which causes build errors. I have therefore abandoned this approach and fixed the build number to 1 in all targets.
This version is a major change that attempt to streamline KeyboardKit and remove or refactor parts that make it hard to maintain. It contains several breaking changes, but I hope that you as a result gets a library that is easier to use and more flexible.
Most notably, the view controller inheritance model has been completely removed. Instead, there is only one KeyboardInputViewController
. It has a stack view to which you can add any views you like, like the built-in KeyboardButtonRow
and KeyboardCollectionView
, which means that your custom keyboards is now based on components that you can combine.
Since KeyboardInputViewController
therefore can display multiple keyboards at once, it doesn't make any sense to have a single keyboard
property. You can still use structs to organize your actions (in fact, I recommend it - have a look at the demo app), but you don't have to.
All action handling has been moved from the view controller to KeyboardActionHandler
as well. KeyboardInputViewController
use a StandardActionHandler
by default, but you can replace this by setting keyboardActionHandler
to any KeyboardActionHandler
. This is required if you want to use certain actions types, like .image
.
New KeyboardAction
s are added and nextKeyboard
has been renamed to switchKeyboard
. Action equality logic has also been removed, so instead of isNone
, you should use == .none
from now on. All help properties like image
and imageName
are removed as well, since they belong in the app. These are the new action types
KeyboardInputViewController
will now resize the extension to the size of the stack view, or any other size constraints you may set. The old setHeight(to:)
function has therefore been removed.
This version upgrades KeyboardKit
to Swift 5. It has many breaking changes:
KeyboardInputViewController
has been renamed to KeyboardViewController
CollectionKeyboardInputViewController
has been renamed to CollectionKeyboardViewController
GridKeyboardInputViewController
has been renamed to GridKeyboardViewController
KeyboardAlerter
has been renamed to KeyboardAlert
ToastAlerter
has been renamed to ToastAlert
ToastAlert
now has two nested view classes View
and Label
ToastAlert
's two style function has changed signatureToastAlerterAppearance
is now an internal ToastAlert.Appearance
structKeyboard
has been given an optional ID, which can be used to uniquely identify a keyboard. This makes it easier to manage multiple keyboards in an app.
KeyboardInputViewController
implements the KeyboardPresenter
protocol, which means that you can set the new optional id
property to make a KeyboardSetting
exclusive to that presenter. This is nice if your app has multiple keyboards. If you do not specify an id, the settings behave just like before.
A PR by micazeve is merged. It limits the current page index that is persisted for a keyboard, to avoid bugs if the page count has changed since persisting the value.