preview에 이어서 안드로이드 커스텀 키보드 만들기 1부를 시작하겠습니다. 3부작으로 작성하려고 노력하였지만 글이 너무 길어져서 4부작으로 늘린 점 죄송합니다 ㅠㅠ
1부에서 주로 다룰 내용은 서비스를 통하여 다른 애플리케이션에서 EditText로 인한 키보드 호출 시 커스텀 키보드를 출력하고 커스텀 키보드의 이벤트를 inputMethodService를 이용하여 다시 EditText를 작성할 수 있도록 만드는 것이 목표입니다. 앞서 말씀드렸듯이 Keyboard객체와 KeyboardView객체를 사용하지 않는 것이 큰 특징이고, 그로 인해 각각의 버튼을 모두 따로 바인드 해야 한다는 번거로움이 존재합니다.(다른 방법이 있다면 알려주세요...ㅠㅠ)
우선 첫번째로 키보드로 정의하기 위한 서비스를 작성합니다.
KeyBoardService라는 클래스를 만들고 다음과 같이 manifest에 작성합니다.
<service
android:name=".KeyBoardService"
android:enabled="true"
android:exported="true"
android:label="MyKeyboard"
android:permission="android.permission.BIND_INPUT_METHOD">
<meta-data
android:name="android.view.im"
android:resource="@xml/xml"/>
<intent-filter>
<action android:name="android.view.InputMethod"/>
</intent-filter>
</service>
<menifest>
xml도 당연히 정의되어야겠죠?
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
<subtype
android:label="MyKeyboard"
android:imeSubtypeMode="keyboard" />
</input-method>
<res/xml/xml.xml>
(수정)서비스를 작성하기 전에 필요한 layout을 먼저 작성하도록 하겠습니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/keyboardBackground">
<FrameLayout
android:id="@+id/keyboard_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
</LinearLayout>
<keyboard_view.xml>
이 KeyboardView의 FrameLayout에 한글, 영문 키보드인 keyboard_action이라는 레이아웃과 특수문자인 keyboard_simbols과 같은 레이아웃을 replace해주는 것입니다.
레이아웃 이름이 keyboard_action인 이유는 제가 만들려는 키보드가 움직이는 키패드를 갖는 키보드이기 때문입니다. 제가 만든 키보드는 추후에 개발이 완료되면 따로 설명하는 시간을 갖도록 하겠습니다.(keyboard_action은 다음 게시물에서 소개됩니다.)
여기까지 작성이 됐으면 이제 서비스를 작성해봅시다.
서비스는 InputMethodService를 상속받아 키보드가 필요한 경우 호출될 수 있도록 하고, 입력방식에 따라 한글, 영어, 숫자, 특수문자 등의 키보드를 출력하도록 keyboardInteractionListener를 생성합니다(interface이기 때문에 따로 생성해야 합니다). 본 코드는 코틀린으로 작성되었습니다. (수정)
interface KeyboardInterationListener{
fun modechange(mode:Int)
}
<KeyboardInteractionListener.kt>
lateinit var keyboardView:LinearLayout
lateinit var keyboardFrame:FrameLayout
lateinit var keyboardKorean:KeyboardKorean
lateinit var keyboardEnglish:KeyboardEnglish
lateinit var keyboardSimbols:KeyboardSimbols
val keyboardInterationListener = object:KeyboardInterationListener{
//inputconnection이 null일경우 재요청하는 부분 필요함
override fun modechange(mode: Int) {
currentInputConnection.finishComposingText()
when(mode){
0 ->{
keyboardFrame.removeAllViews()
keyboardEnglish.inputConnection = currentInputConnection
keyboardFrame.addView(keyboardEnglish.getLayout())
}
1 -> {
if(isQwerty == 0){
keyboardFrame.removeAllViews()
keyboardKorean.inputConnection = currentInputConnection
keyboardFrame.addView(keyboardKorean.getLayout())
}
else{
keyboardFrame.removeAllViews()
keyboardFrame.addView(KeyboardChunjiin.newInstance(applicationContext, layoutInflater, currentInputConnection, this))
}
}
2 -> {
keyboardFrame.removeAllViews()
keyboardSimbols.inputConnection = currentInputConnection
keyboardFrame.addView(keyboardSimbols.getLayout())
}
3 -> {
keyboardFrame.removeAllViews()
keyboardFrame.addView(KeyboardEmoji.newInstance(applicationContext, layoutInflater, currentInputConnection, this))
}
}
}
}
<KeyboardService.kt>
위와같이 modechange라는 함수를 만들고 정의합니다. 작성 중인 텍스트를 commit 하기 위한 finishComposingText를 호출하고, 매개변수인 mode에 따라 필요한 키보드를 출력할 수 있도록 framelayout에 추가합니다(성능 비교를 위하여 KeyboardKorean 클래스는 싱글톤 구조를 따르지 않도록 변경하였습니다).
다음으로 InputMethodService의 생명주기에 따라 필요한 기능을 초기화합니다.
InputMethodService의 생명주기는 이곳에서 참고하시면 좋을 것으로 보입니다.(https://sites.google.com/site/endihom/home/programming-language/android/article/input-method)
우선, Oncreate함수에서 keyboard가 될 전체 레이아웃과 입력방식에 따라 다르게 채워질 framglayout을 정의합니다.
override fun onCreate() {
super.onCreate()
keyboardView = layoutInflater.inflate(R.layout.keyboard_view, null) as LinearLayout
sharedPreferences = getSharedPreferences("setting", Context.MODE_PRIVATE)
keyboardFrame = keyboardView.findViewById(R.id.keyboard_frame)
}
<KeyboardService.kt>
그런 뒤 onCreateInputView에서 위에서 정의한 추가하려고하는 keyboardView를 리턴합니다.(실제로 EditText에 포커스가 갈 경우 호출되는 View라고 할 수 있습니다)(수정)
override fun onCreateInputView(): View {
keyboardKorean = KeyboardKorean(applicationContext, layoutInflater, keyboardInterationListener)
keyboardEnglish = KeyboardEnglish(applicationContext, layoutInflater, keyboardInterationListener)
keyboardSimbols = KeyboardSimbols(applicationContext, layoutInflater, keyboardInterationListener)
keyboardKorean.inputConnection = currentInputConnection
keyboardKorean.init()
keyboardEnglish.inputConnection = currentInputConnection
keyboardEnglish.init()
keyboardSimbols.inputConnection = currentInputConnection
keyboardSimbols.init()
return keyboardView
}
<KeyboardService.kt>
마지막으로 updateInputViewShown이라는 함수에서 현재 필요한 키보드를 결정하고 수정합니다. 앞서 정의한 FrameLayout에 키보드를 추가할 수 있는 keyboardInteractionListener의 modechange함수를 이용합니다. 여기서는 keyboardNumpad는 따로 추가하였습니다.(코드 정리가 부족하네요... 죄송합니다 ㅠㅠ)
서비스로 동작하는 애플리케이션이라서 그런지 이 메소드에서 inputConnection을 초기화하지 않으면 계속해서 EditText와의 연결이 끊어지는 현상을 발견할 수 있었습니다.
override fun updateInputViewShown() {
super.updateInputViewShown()
currentInputConnection.finishComposingText()
isQwerty = sharedPreferences.getInt("keyboardMode", 0)
if(currentInputEditorInfo.inputType == EditorInfo.TYPE_CLASS_NUMBER){
keyboardFrame.removeAllViews()
keyboardFrame.addView(KeyboardNumpad.newInstance(applicationContext, layoutInflater, currentInputConnection, keyboardInterationListener))
}
else{
keyboardInterationListener.modechange(1)
}
}
<KeyboardService.kt>
여기까지 작성이 완료되었으면 우선 키보드를 출력하기 위한 기본은 모두 작성이 완료된 상태입니다. 앞으로 필요한 작업은 KeyboardEnglish, KeyboardKorean, KeyboardNumPad, KeyboardSimbols, KeyboardEmoji와 같은 클래스를 작성하고 해당 클래스에서 inputConnection을 통하여 EditText에 글자를 채워 넣기만 하면 됩니다.
전체적인 코드 흐름을 보면 다음과 같습니다.
다음 시간에는 간단한 영어 키보드 제작까지 마무리해보도록 하겠습니다. 두서없는 글 읽어주셔서 감사드립니다 !!
*(수정)성능 개선을 위하여 onCreateInputView에서 init한 KeyboardKorean객체를 재활용할 수 있도록 개선하였습니다(2019.11.08)
'IT 프로그래밍-Android' 카테고리의 다른 글
[Android]커스텀 키보드 만들기(4/4) - 천지인 키보드 만들기 (0) | 2019.11.12 |
---|---|
[Android] 커스텀 키보드 만들기(3/4) 외전 - HangulMaker (2) | 2019.11.08 |
[Android] 커스텀 키보드 만들기(3/4) - 쿼티 키보드 만들기 (7) | 2019.11.08 |
[Android] 커스텀 키보드 만들기(2/4) - 영문 키보드 만들기 (1) | 2019.11.05 |
[Android] 키보드 앱 만들기 (9) | 2019.10.25 |