•  


GitHub - paescebu/CustomKeyboardKit: Creating custom In App Keyboards with SwiftUI has never been easier!
Skip to content

Creating custom In App Keyboards with SwiftUI has never been easier!

License

Notifications You must be signed in to change notification settings

paescebu/CustomKeyboardKit

Repository files navigation

CustomKeyboardKit

I strongly believe that any in app keyboard layout is best built in SwiftUI, no matter if its used in SwiftUI or UIKit. With that lightweight package I think I offer you the necessary tools to do so in the UI Framework that we all started to embrace and love. SwiftUI!

My goal is to keep this framework as lightweight as it is, to not add bloat to it with features most people do not need. This ensures keeping the complexity of the package at its minimum, which translates to a certain stability and reliability. I sincerely hope with this package I managed to deliver pretty much unrestricted possibilities for you.

Features

  • Build the entire keyboard layout in SwiftUI
    • Doesn't even have to be a keyboard, build literally anything that pops up for focused text fields!
  • Can play native iOS/iPadOS keyboard sounds and haptic feedback
  • Use it in UIKit or SwiftUI
  • Interact with the focused text using the UITextDocumentProxy closure parameter
  • Use it parallelly to any native keyboard
  • Works with SwiftUI's new scrollDismissesKeyboard(:) modifiers etc.
  • Works flawlessly on iOS and iPadOS
  • Works with the native onSubmit modifier, but behaviour can be fully customized by using onCustomSubmit instead

Creating the Keyboard

Simply extend the CustomKeyboard class and provide a static computed property and use the CustomKeyboardBuilder, additionally use the UITextDocumentProxy instance to modify/delete the focused text and move the cursor. Use the playSystemFeedback closure to play system sounds on Button presses. See the example below:

extension
 CustomKeyboard
 {

    static
 var
 yesnt
:
 CustomKeyboard
 {

        CustomKeyboardBuilder
 {
 textDocumentProxy
,
 submit
,
 playSystemFeedback 
in

            VStack
 {

                HStack
 {

                    Button
(
"
Yes!
"
)
 {

                        textDocumentProxy
.
insertText
(
"
Yes
"
)

                        playSystemFeedback
?
(
)

                    }

                    Button
(
"
No!
"
)
 {

                        textDocumentProxy
.
insertText
(
"
No
"
)

                        playSystemFeedback
?
(
)

                    }

                }

                Button
(
"
Maybe
"
)
 {

                    textDocumentProxy
.
insertText
(
"
?
"
)

                    playSystemFeedback
?
(
)

                }

                Button
(
"
Idk
"
)
 {

                    textDocumentProxy
.
insertText
(
"
Idk
"
)

                    playSystemFeedback
?
(
)

                }

                Button
(
"
Can you repeat the question?
"
)
 {

                    playSystemFeedback
?
(
)

                    submit
(
)

                }

            }

            .
buttonStyle
(
.
bordered
)

            .
padding
(
)

        }

    }

}

Using Your Custom Keyboard In SwiftUI

Once declared, you can use the custom keyboard with the .customKeyboard(:) View modifer and using your statically defined property

struct
 ContentView
:
 View
 {

    @
State
 var
 text
:
 String
 =
 "
"


    var
 body
:
 some
 View
 {

        VStack
 {

            Text
(
text
)

            TextField
(
"
"
,
 text
:
 $text
)

                .
customKeyboard
(
.
yesnt
)

        }

    }

}

About Customizing The Submit Button Tap Behaviour

The custom keyboard supports the native onSubmit modifier to pass a closure to perform actions after the submit button has been tapped. In order to fully customize the behaviour of the submit button to not follow the native behaviour (e.g. not closing the keyboard) the onCustomSubmit modifier shall be used.

struct
 ContentView
:
 View
 {

    @
State
 var
 text
:
 String
 =
 "
"


    var
 body
:
 some
 View
 {

        VStack
 {

            Text
(
text
)

            TextField
(
"
"
,
 text
:
 $text
)

                .
customKeyboard
(
.
yesnt
)

                .
onCustomSubmit
 {

                    print
(
"
do something when SubmitHandler has been called
"
)

                }


        }

    }

}

If both modifiers are used onCustomSubmit takes precedence over onSubmit and performs the closure inside onCustomSubmit only. So please make sure to only use one of the two ideally.

Using Your Custom Keyboard In UIKit

Once declared, you can assign your CustomKeyboard 's keyboardInputView property to the UITextFields inputView .

override
 func
 viewDidLoad
(
)
 {

    super
.
viewDidLoad
(
)

    // Do any additional setup after loading the view.

    let
 customKeyboard
 =
  CustomKeyboard
.
yesnt
    customKeyboard
.
onSubmit 
=
 {
 print
(
"
do something when SubmitHandler called
"
)
 }


    myTextField
.
inputView 
=
 customKeyboard
.
keyboardInputView
}

Alternative direct SwiftUI use:

You can also directly use the customKeyboard(view:) modifier that allows you to build the custom keyboard within the view body itself, if you need to access some View properties or constants etc. Example:

struct
 ContentView
:
 View
 {

    @
State
 var
 text
 =
 "
0
"

    
    var
 body
:
 some
 View
 {

        TextField
(
"
"
,
 text
:
 $text
)

            .
customKeyboard
 {
 textDocumentProxy
,
 onSubmit
,
 playFeedback 
in

                VStack
 {

                    numberButton
(
text
:
 "
1
"
,
 uiTextDocumentProxy
:
 textDocumentProxy
,
 playFeedback
:
 playFeedback
)

                    numberButton
(
text
:
 "
2
"
,
 uiTextDocumentProxy
:
 textDocumentProxy
,
 playFeedback
:
 playFeedback
)

                    Button
(
"
DEL
"
)
 {

                        textDocumentProxy
.
deleteBackward
(
)

                        playFeedback
?
(
)

                    }

                }

            }

    }

    
    func
 numberButton
(
text
:
 String
,
 uiTextDocumentProxy
:
 UITextDocumentProxy
,
 playFeedback
:
 (
(
)
 ->
 (
)
)
?
)
 ->
 some
 View
 {

        Button
(
text
)
 {

            uiTextDocumentProxy
.
insertText
(
text
)

            playFeedback
?
(
)

        }

    }

}

This works equally with TextEditor

Complete Example

Check out the video below for the following example code and see how it works perfectly side by side with native keyboards.

struct
 ContentView
:
 View
 {

    @
State
 var
 text0
:
 String
 =
 "
"

    @
State
 var
 text1
:
 String
 =
 "
"

    @
State
 var
 text2
:
 String
 =
 "
"

    @
State
 var
 text3
:
 String
 =
 "
"


    var
 body
:
 some
 View
 {

        VStack
 {

            Group
 {

                TextField
(
"
ABC
"
,
 text
:
 $text0
)

                    .
customKeyboard
(
.
alphabet
)

                TextField
(
"
Numpad
"
,
 text
:
 $text1
)

                    .
keyboardType
(
.
numberPad
)

                TextField
(
"
ABC
"
,
 text
:
 $text2
)

                    .
customKeyboard
(
.
alphabet
)

                TextField
(
"
Normal
"
,
 text
:
 $text3
)

                    //normal keyboard

            }

            .
background
(
Color
.
gray
)

        }

        .
padding
(
)

    }

}


extension
 CustomKeyboard
 {

    static
 var
 alphabet
:
 CustomKeyboard
 {

        CustomKeyboardBuilder
 {
 textDocumentProxy
,
 submit
,
 playSystemFeedback 
in

            let
 letters
 =
 "
ABCDEFGHIJKLMNOPQRSTUVWXYZ
"
.
map
 {
 $0 
}

            let
 gridItem
 =
 GridItem
.
init
(
.
adaptive
(
minimum
:
 25
)
)


            return
 LazyVGrid
(
columns
:
 [
gridItem
]
,
 spacing
:
 5
)
 {

                ForEach
(
letters
,
 id
:
 \
.
self
)
 {
 char 
in

                    Button
(
char
.
uppercased
(
)
)
 {

                        textDocumentProxy
.
insertText
(
"
\(
char
)
"
)

                        playSystemFeedback
?
(
)

                    }

                    .
frame
(
width
:
 25
,
 height
:
 40
)

                    .
background
(
Color
.
white
)

                    .
foregroundColor
(
Color
.
black
)

                    .
cornerRadius
(
8
)

                    .
shadow
(
radius
:
 2
)

                }

            }

            .
frame
(
height
:
 150
)

            .
padding
(
)

        }

    }

}
Simulator.Screen.Recording.-.iPhone.14.-.2022-11-29.at.19.00.36.mp4

Warranty

The code comes with no warranty of any kind. I hope it'll be useful to you (it certainly is to me), but I make no guarantees regarding its functionality or otherwise.

Donations

You really don't have to pay anything to use this package. But if you feel generous today and would like to donate because this package helped you so much, here's a PayPal donation link: https://www.paypal.com/donate/?hosted_button_id=JYL8DBGA2X4YQ

or just buy me a hot chocolate: https://www.buymeacoffee.com/paescebu

- "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
- "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
- 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
- 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
 한국   대만   중국   일본