根据Android系统源码拨号应用的键盘的实现方式实现进行实现 之前有个需求是和手机拨号键盘一样类似的需求,虽然之前也做过类似的需求,但是觉得之前的实现不够优雅和完善,刚好因为一些原因在对源码进行各种探究,于是顺便看看源码中的拨号键盘是如何实现. 最开始也在网上进行了一些查找,不过比较细致和完善的也没有,这里直接把系统源码中的实现进行完整展示. 拨号的系统应用是Dialer,对这部分的处理在它的依赖库PhoneCommon和InCallUI中,具体路径如下:
PhoneCommon com.android.phone.common.dialpad.DigitsEditText PhoneCommon\res\layout\dialpad_view_unthemed.xml InCallUI com.android.phone.common.dialpad.DialpadView 
 
处理要点 
进入界面和点击EditText时不弹出系统输入法 
保持EditText按住时左右滑动文字也进行滑动效果 
未输入和在最末尾输入时一般不显示光标,在中间时进行显示 
有时是设置为可以点击将光标移动到中央,有时是禁用点击将光标移动到文字中 
禁用点击移动光标时进行滑动到中间后继续输入会自动跳转到末尾 
将选择的字符输入到EditText 
 
禁用系统输入法 1. EditText简单自定义 这里直接贴出PhoneCommon中的源码
public  class  DigitsEditText  extends  EditText   {    public  DigitsEditText (Context context, AttributeSet attrs)   {         super (context, attrs);         setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);         setShowSoftInputOnFocus(false );     }     @Override      protected  void  onFocusChanged (boolean  focused, int  direction, Rect previouslyFocusedRect)   {         super .onFocusChanged(focused, direction, previouslyFocusedRect);         final  InputMethodManager imm = ((InputMethodManager) getContext()                 .getSystemService(Context.INPUT_METHOD_SERVICE));         if  (imm != null  && imm.isActive(this )) {             imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0 );         }     }     @Override      public  boolean  onTouchEvent (MotionEvent event)   {         final  boolean  ret = super .onTouchEvent(event);                  final  InputMethodManager imm = ((InputMethodManager) getContext()                 .getSystemService(Context.INPUT_METHOD_SERVICE));         if  (imm != null  && imm.isActive(this )) {             imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0 );         }         return  ret;     } } 
 
SUGGESTIONS是禁用拼写检查,其他的处理和网上的一些帖子说的一样,就是在点击效果时隐藏掉输入法
<DigitsEditText      android:background ="@android:color/transparent"      android:cursorVisible ="false"      android:focusableInTouchMode ="true"      android:freezesText ="true"      android:gravity ="center"      android:maxLines ="1"      android:scrollHorizontally ="true"      android:singleLine ="true"      android:textCursorDrawable ="@null" /> 
 
这是源码中进行使用时的一些配置 cursorVisible是光标默认显示隐藏 freezesText是旋转时会保存已输入的内容
2. 进入界面时不弹出软键盘 即使自定义了EditText,但是在进入界面时如果未进行配置还是会因为光标会默认找寻EditText进行选中弹出 这里有2种方式进行解决:
界面打开时焦点默认选中到别处  在EditText的父控件上设置两个属性
 android:focusable="true" android:focusableInTouchMode="true" 
 
 
在AndroidManifest中对该界面的输入法弹出行为进行配置  在Activity配置android:windowSoftInputMode="stateAlwaysHidden|adjustNothing"即可
 
 
点击和光标的处理 点击和光标由以下几个方法进行控制:
EditText.setClickable(Boolean); EditText.setLongClickable(Boolean); EditText.setFocusableInTouchMode(Boolean); EditText.setCursorVisible(Boolean); 
 
1. 可进行点击来移动光标位置,长按具有选中全部效果 具体效果就是手机中拨号键盘输入后未播出时的效果
将上述4个方法中前3个全部置为true 
因为开始默认设置了光标不显示,如果有输入内容时点击显示光标  设置点击效果: if  (content.etInput.length() != 0 ) {    content.etInput.isCursorVisible = true  } 
 
输入内容清空时隐藏光标etInput.addTextChangedListener(this ) override  fun  afterTextChanged (s: Editable )   {     if  (etInput.length() == 0 ) {          etInput.isCursorVisible = false       } } 
 
在末尾继续输入时隐藏光标  参加下面进行输入的keyPressed方法中的处理 
 
2. 只能继续末尾输入和滑动查看,滑动到中间进行输入自动跳到末尾 具体效果也就是手机中播出接通后进行输入时的效果 将上面的四个方法全部置为false即可
优雅的进行输入 虽然直接setText()也是可以进行输入控制,不过源码中的方式更为优雅,并且直接setText()在是插入时需要进行额外处理
android.view.KeyEvent中定义了键盘输入的所有键值,比如0-9对应KeyEvent.KEYCODE_0-9
EditText继承于TextView的onKeyDown(int keyCode, KeyEvent event)方法即可进行输入,并且根据光标位置进行插入
R.id.tvNum0 -> keyPressed(KeyEvent.KEYCODE_0) R.id.tvNum1 -> keyPressed(KeyEvent.KEYCODE_1) R.id.tvNum2 -> keyPressed(KeyEvent.KEYCODE_2) R.id.tvNum3 -> keyPressed(KeyEvent.KEYCODE_3) R.id.tvNum4 -> keyPressed(KeyEvent.KEYCODE_4) R.id.tvNum5 -> keyPressed(KeyEvent.KEYCODE_5) R.id.tvNum6 -> keyPressed(KeyEvent.KEYCODE_6) R.id.tvNum7 -> keyPressed(KeyEvent.KEYCODE_7) R.id.tvNum8 -> keyPressed(KeyEvent.KEYCODE_8) R.id.tvNum9 -> keyPressed(KeyEvent.KEYCODE_9) R.id.tvSymbolAsterisk -> keyPressed(KeyEvent.KEYCODE_STAR) R.id.tvSymbolPoundSign -> keyPressed(KeyEvent.KEYCODE_POUND) private  fun  keyPressed (keyCode: Int )   {    etInput.onKeyDown(keyCode, KeyEvent(KeyEvent.ACTION_DOWN, keyCode))               val  length = content.etInput.length()     if  (length == etInput.selectionStart && length == etInput.selectionEnd) {         etInput.isCursorVisible = false      } } 
 
 
源码中对实现EditText自定义键盘进行输入的基本内容如上述,在源码中还有很多额外处理,比如按键音的播放也在其中,有兴趣和需要的可以自行查看.