问题
I did my custom pin-code view
class StarsPasswordView : LinearLayout {
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init(context, attrs)
}
val passwordHolder = SpannableStringBuilder()
var count
fun init(context: Context, attrs: AttributeSet?) {
orientation = HORIZONTAL
isFocusable = true
isFocusableInTouchMode = true
gravity = Gravity.CENTER
val attr = context.obtainStyledAttributes(attrs, R.styleable.StarsPasswordView, 0, 0)
count = attr.getInteger(R.styleable.StarsPasswordView_count, 4)
attr.recycle()
drawView(count)
setOnKeyListener(View.OnKeyListener { v, keyCode, event ->
if (event.action == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_ENTER)
return@OnKeyListener true
if (keyCode == KeyEvent.KEYCODE_BACK)
return@OnKeyListener false
if (keyCode == KeyEvent.KEYCODE_DEL) {
clear()
get(0).requestFocus()
} else
if (passwordHolder.length != count) {
passwordHolder.append(event.number)
val position = passwordHolder.length
select(position - 1)
if (position < count)
get(position).requestFocus()
else {
passwordFilled?.invoke(passwordHolder.toString())
}
}
return@OnKeyListener true
}
false
})
}
fun samsungWorkaround() {
val position = passwordHolder.length
select(position - 1)
if (position == count)
passwordFilled?.invoke(passwordHolder.toString())
}
}
// toggle whether the keyboard is showing when the view is clicked
override fun onTouchEvent(event: MotionEvent): Boolean {
if (enableKeyboard && event.action == MotionEvent.ACTION_UP) {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY)
}
return true
}
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
return InputConnection(this, true)
}
}
class InputConnection internal constructor(val targetView: StarsPasswordView, fullEditor: Boolean) : BaseInputConnection(targetView, fullEditor) {
override fun getEditable(): Editable {
return targetView.passwordHolder
}
override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean {
val res = super.commitText(text, newCursorPosition)
targetView.samsungWorkaround()
return res
}
}
The problem comes when you want to set
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
at this case
InputConnection
doesn't handle numbers- getEditable() doesn't fire
commitText() doesn't fire
so my workaround was just handling numbs in setOnKeyListener as you can see above.
Does anyone know what the issue is?
回答1:
Depending on the keyboard, not all keys are sent through the InputConnection
. Some are sent like hard keys events and must be processed separately. This includes the number pad numbers on the standard keyboard. To the best of my current knowledge, using the OnKeyListener
like you did is the way to go (but see @pskink's comments here).
You can separate the text characters from the control characters with KeyEvent.getUnicodeChar()
as is shown below.
if (keyEvent.getUnicodeChar() != 0) {
// unicode text
char unicodeChar = (char) keyEvent.getUnicodeChar();
} else {
// control char
}
Handle the control codes that you need, but all the valid Unicode characters (including numbers and the new line (enter) character) will be caught.
I cover some aspects of this in more detail in the question and answers I wrote while preparing to answer this question.
- Differentiating text keycode from control keycode in Android KeyEvent
- Need table of key codes for android and presenter
I also updated my previous answer about custom views receiving keyboard input.
来源:https://stackoverflow.com/questions/44969327/input-connection-for-numeric-type-keyboard