概要
Androidで1文字ずつ文字の検出をしようと思ってonKey~をつかってもできませんでした.
ちょっと調べたところ,ソフトウェアキーボードのキーボードイベントを拾ってくれないらしいです.
https://developer.android.com/training/keyboard-input/commands
ので,1文字ずつ文字の検出する機能を実装しました.
EditTextの場合,TextChangedListenerを使えば一応できますが,入力ではなくてEditTextのテキストが変わったら反応するため処理がめんどくさいので使いません.
ソースコード
実装
今回はEditTextの場合で実装していきます.
この実装方法だと(たぶん)ほかのViewでもつかえます.WebViewでは使えました.
やることは簡単で,もとになるViewを継承してonCreateInputConnection
とdispatchKeyEvent
をオーバーライトするだけです.
dispatchKeyEvent
でKeyEvent
を拾えるので,そこで入力時にしたいことを記述します.
package com.usr.myedittexttest
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.inputmethod.BaseInputConnection
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.widget.EditText
class MyEditText : EditText {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
return BaseInputConnection(this, false)
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
val dispatchFirst = super.dispatchKeyEvent(event)
if (event.action == KeyEvent.ACTION_UP){
val charCode = event.unicodeChar
// 入力時の処理
Log.d("MyEditText", "onKey keyCode=$charCode")
Log.d("MyEditText", "onKey input=${charCode.toChar()}")
}
return dispatchFirst
}
}
新しいViewはもとのViewと同じように使用できます.
package com.usr.myedittexttest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
lateinit var myEditText: MyEditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myEditText = findViewById(R.id.my_edit)
}
}
activity_main.xml
は使うViewを作成したものに変更します.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.usr.myedittexttest.MyEditText
android:id="@+id/my_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
入力を通知するListenerを作成する場合
入力したことを通知するListenerを使ったほうが便利なのでListenerを作成します.
まずListenerを作成
package com.usr.myedittexttest
import java.util.*
interface InputListener: EventListener {
fun onKey(text: Char)
}
次にMyEditText
を少し改造
package com.usr.myedittexttest
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.inputmethod.BaseInputConnection
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.widget.EditText
class MyEditText : EditText {
private var listener: InputListener? = null
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
return BaseInputConnection(this, false)
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
val dispatchFirst = super.dispatchKeyEvent(event)
if (event.action == KeyEvent.ACTION_UP){
val charCode = event.unicodeChar
// 入力時の処理
Log.d("MyEditText", "onKey keyCode=$charCode")
Log.d("MyEditText", "onKey input=${charCode.toChar()}")
// 入力を通知
listener?.onKey(charCode.toChar())
}
return dispatchFirst
}
fun setListener(listener: InputListener){
this.listener = listener
}
}
MainActivity
では入力の通知を受け取った時の処理を記述します.
そのためにInputListenerを実装します.
通知を受け取るとonKey
が呼ばれるので,そこに処理を記述してください.
package com.usr.myedittexttest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
class MainActivity : AppCompatActivity(), InputListener{
lateinit var myEditText: MyEditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myEditText = findViewById(R.id.my_edit)
myEditText.setListener(this)
}
override fun onKey(text: Char) {
Log.d("MainActivity", "text=$text")
// TODO something
}
}
終わりに
勉強し始めたばかりですので,より良い方法があるかと思います.よろしければお教えくださいますと幸いです.