之前上传的另外一个自定义键盘,并没有实现键盘弹出的时候,布局向上自动调整。(网络上所有的自定义键盘都没有添加自适应的功能,而且布局没这么好看,上一个例子资源链接为:http://download.csdn.net/detail/omayyouhappy/9111809,这个资源绝对值10分,真的全网络唯一完美的自定义定制键盘,新的资源在这里:全网唯一定制键盘(向上改变布局)   ,接下来就仔细的讲讲我是如何完成自定义键盘的,我得吐槽一下,一开始为了做自定义键盘,网上的例子确实很有用,避免了重复造轮子,给了我很大的启示,也快速的知道如何使用google提供的自定义键盘类使用方法,介绍几本的键盘的情况,你可以到这篇博文来了解: 整个网络可能最完善的 Android 自定义键盘 问题汇总以及解决方案,只需要花几分钟时间,就可以制作一个几本的键盘,但这个键盘有很多缺点,是通过按钮隐藏布局的形式来隐藏键盘、有可能会出现遮挡住你所要输入的edittext情况,无法适应整个屏幕布局,这篇博文就是讲解如何解决这些问题的,那么开始吧:

自定义键盘整个过程如下:

1.第一步,根据你的需求,需要定制怎样的键盘,需要几行几列,准备好键盘按键的背景图片,键盘的尺寸,在res文件下,新建一个xml文件,下面放字母、数字、标点符号键盘的布局文件,我的需求是这样的:

可以看到上述的键盘需要美工做的图片有几张:字母和数字的按键的基本背景(需要圆角)、删除按键、切换大小写的图标、点击隐藏键盘的下拉按键,设置键盘的布局为白色就可以大致实现上述的效果。这里我在写键盘文件的时候遇到几个难点,分享如下:

A.按键之间的空隙和键盘整体高度,需要不断的调整,不可能一下子就可以布置好的,特别字母键盘里的删除键,高度是两个按键,所以需要反复调试。

B.为了解决点击下拉按钮隐藏键盘的功能:放弃原先点击下拉按钮,隐藏整个键盘的布局的方案,而改用在键盘文件中再加一整行,只有一个按键,就是done,完成按钮,这是系统定义好的完成功能,code值为:  -3。(所以我们发现很多系统自动的比如切换大小写、删除功能、空格功能,都是已经定义好了code值,只需要找到对应的含义,直接定义使用就可以了。)

字母布局文件如下(主要部分,代码可以到资源里下载):res\xml\qwerty.xml

[html] view plaincopy print?
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:horizontalGap="1px"
  4. android:keyWidth="9.7%p"
  5. android:verticalGap="3px" >
  6. <Row android:verticalGap="18px" >
  7. <Key
  8. android:codes="-3"
  9. android:keyIcon="@drawable/ret"
  10. android:keyWidth="100%p" />
  11. </Row>
  12. 。。。。。。。。。。。。。。。
[html] view plaincopy print?
  1. 。。。。。。。。。。。。
  2. <Row android:keyHeight="40dp" >
  3. <Key
  4. android:codes="-1"
  5. android:keyEdgeFlags="left"
  6. android:keyIcon="@drawable/updata"
  7. android:keyWidth="9.55%p" />
  8. <Key
  9. android:codes="-4"
  10. android:keyLabel=".?&" />
  11. <Key
  12. android:codes="122"
  13. android:keyLabel="z" />
  14. <Key
  15. android:codes="120"
  16. android:keyLabel="x" />
  17. <Key
  18. android:codes="99"
  19. android:keyLabel="c" />
  20. <Key
  21. android:codes="118"
  22. android:keyLabel="v" />
  23. <Key
  24. android:codes="98"
  25. android:keyLabel="b" />
  26. <Key
  27. android:codes="110"
  28. android:keyLabel="n" />
  29. <Key
  30. android:codes="109"
  31. android:keyLabel="m" />
  32. </Row>
  33. </Keyboard>

标点符号键盘布局文件如下:res\xml\qwerty2.xml

[html] view plaincopy print?
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:horizontalGap="1px"
  4. android:keyWidth="9.7%p"
  5. android:verticalGap="3px" >
  6. <Row android:verticalGap="18px">
  7. <Key
  8. android:codes="-3"
  9. android:keyIcon="@drawable/ret"
  10. android:keyWidth="100%p"
  11. android:verticalGap="3px"  />
  12. </Row>
[html] view plaincopy print?
  1. 。。。。。。。。。。。。。。。。。。。。。。<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">。。。。。。。。。。。。。。。。。。。</span>
[html] view plaincopy print?
  1. <Row android:keyHeight="40dp" >
  2. <Key
  3. android:codes="-1"
  4. android:isSticky="true"
  5. android:keyIcon="@drawable/updata" />
  6. <Key
  7. android:codes="-4"
  8. android:keyLabel="abc" />
  9. <Key
  10. android:codes="96"
  11. android:keyLabel="`" />
  12. <Key
  13. android:codes="32"
  14. android:isRepeatable="true"
  15. android:keyLabel="space"
  16. android:keyWidth="39%p" />
  17. <Key
  18. android:codes="46"
  19. android:keyLabel="." />
  20. <Key
  21. android:codes="44"
  22. android:keyLabel="," />
  23. </Row>
  24. /Keyboard>

数字键盘布局如下:(其中一些按键是自定义的,比如10,000,000,这是为了用户输入方便):res\xml\amountinputkeyboard.xml

[html] view plaincopy print?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:horizontalGap="3px"
  4. android:keyWidth="24.2%p"
  5. android:verticalGap="3px" >
  6. <Row android:verticalGap="18px" >
  7. <Key
  8. android:codes="-3"
  9. android:keyIcon="@drawable/ret"
  10. android:keyWidth="100%p"
  11. android:verticalGap="3px" />
  12. </Row>
  13. 。。。。。。。。。。。。。
[html] view plaincopy print?
  1. 。。。。。。。。。。。。。
  2. <Row android:keyHeight="50dp" >
  3. <Key
  4. android:codes="46"
  5. android:keyLabel="." />
  6. <Key
  7. android:codes="48"
  8. android:keyLabel="0" />
  9. <Key
  10. android:codes="-110"
  11. android:keyLabel="00" />
  12. <Key
  13. android:codes="-5"
  14. android:isRepeatable="true"
  15. android:keyEdgeFlags="right"
  16. android:keyIcon="@drawable/deletepng" />
  17. </Row>
  18. </Keyboard>

上面的节点具体解释可以参照上篇博文,我分享一下我与网络最热那篇自定义键盘的区别:为了加一整行的点击隐藏按键,需要单独设置高度和间距,所以我们不在xml开头设置整体的键盘高度,而改在Row节点上进行单独的高度设置,这一点非常重要,如果设置整体的高度,就会出现最上面一行有多余的白色部分,影响美观:也就是下面这个:

[html] view plaincopy print?
  1. <Row <span style="color:#ff0000;"><strong>android:verticalGap="18px"</strong></span> >
  2. <Key
  3. android:codes="-3"
  4. android:keyIcon="@drawable/ret"
  5. android:keyWidth="100%p"
  6. android:verticalGap="3px" />
  7. </Row>

对于键盘之间的垂直和水平方向的间距多少合适,以及每个按键占据的百分比多少合适,都要根据你所使用的手机、按键背景图片大小、有几行按键来细心调整,在这段代码进行调整:

[html] view plaincopy print?
  1. <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:horizontalGap="3px"
  3. android:keyWidth="24.2%p"
  4. android:verticalGap="3px" </strong>

2.定义好了你所需要的键盘布局,已经完成了关键性的一步,下面就是如何在点击edit之后,隐藏系统键盘,弹出自定义键盘,点击按钮隐藏键盘等功能。

第二步,建立你所需要放置自定义键盘的主布局文件,如下:

[html] view plaincopy print?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:mykeyboard="http://schemas.android.com/apk/res/com.example.testkeyboard"
  3. android:id="@+id/fulllayout"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:orientation="vertical" >
  7. <com.example.testkeyboard.MyKeyboard// 自定义<span style="font-family: Arial, Helvetica, sans-serif;">EditText,继承于EditText,实现键盘implements OnKeyboardActionListener接口
  8. android:id="@+id/et"
  9. android:layout_width="match_parent"
  10. android:layout_height="30dp"
  11. android:layout_marginTop="10dp"
  12. android:background="@drawable/gray_shape" //设置圆角效果
  13. android:gravity="center"
  14. android:hint="身份证号"
  15. android:singleLine="true"
  16. android:textColor="@color/black"
  17. android:textColorHint="#BABABA"
  18. mykeyboard:xml="@xml/amountinputkeyboard" />  //
  19. <com.example.testkeyboard.MyKeyboard
  20. android:id="@+id/etChar"
  21. android:layout_width="match_parent"
  22. android:layout_height="30dp"
  23. android:layout_marginTop="10dp"
  24. android:background="@drawable/gray_shape"
  25. android:gravity="center"
  26. android:hint="字母和标点符号键盘"
  27. android:singleLine="true"
  28. android:textColor="@color/black"
  29. android:textColorHint="#BABABA"
  30. mykeyboard:xml="@xml/qwerty" />
  31. </LinearLayout>

键盘单独布局文件: res\layout\mykeyboardview.xml

[html] view plaincopy print?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"//系统自带的键盘布局文件
  3. android:id="@+id/keyboard_view"
  4. android:layout_width="fill_parent"
  5. android:layout_height="wrap_content"
  6. android:layout_alignParentBottom="true"
  7. <span style="color:#ff0000;"> android:background="@color/white"  //设置键盘的整个背景为白色</span>
  8. android:focusable="true"
  9. android:focusableInTouchMode="true"
  10. android:keyBackground="@drawable/d"
  11. android:keyTextColor="#A8AAAB"
  12. android:keyTextSize="20sp"
  13. android:labelTextSize="15sp"
  14. android:padding="2.5dp" />
  15. <!-- android:keyBackground="@drawable/data" -->

该类主要是让主控制类加载。

第三步:编写主控制类:主要显示键盘和控制键盘动画隐藏弹出效果,主控制类:src\com\example\testkeyboard\MyKeyboard.java,主要代码注释如下:

[java] view plaincopy print?
  1. package com.example.testkeyboard;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.Method;
  4. import java.security.SecureRandom;
  5. import java.util.ArrayList;
  6. import java.util.LinkedList;
  7. import java.util.List;
  8. import java.util.Random;
  9. import android.annotation.TargetApi;
  10. import android.app.Activity;
  11. import android.content.Context;
  12. import android.content.res.TypedArray;
  13. import android.graphics.Rect;
  14. import android.inputmethodservice.Keyboard;
  15. import android.inputmethodservice.Keyboard.Key;
  16. import android.inputmethodservice.KeyboardView;
  17. import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
  18. import android.os.Build;
  19. import android.os.SystemClock;
  20. import android.text.Editable;
  21. import android.util.AttributeSet;
  22. import android.util.DisplayMetrics;
  23. import android.view.ActionMode;
  24. import android.view.Display;
  25. import android.view.Gravity;
  26. import android.view.KeyEvent;
  27. import android.view.LayoutInflater;
  28. import android.view.Menu;
  29. import android.view.MenuItem;
  30. import android.view.MotionEvent;
  31. import android.view.View;
  32. import android.view.ViewGroup;
  33. import android.view.Window;
  34. import android.view.WindowManager;
  35. import android.view.inputmethod.EditorInfo;
  36. import android.view.inputmethod.InputMethodManager;
  37. import android.widget.EditText;
  38. import android.widget.PopupWindow;
  39. import android.widget.PopupWindow.OnDismissListener;
  40. /**
  41. *
  42. * 自定义键盘,有按下效果
  43. *
  44. */
  45. public class MyKeyboard extends EditText implements OnKeyboardActionListener {
  46. private Keyboard k1;// 字母键盘
  47. private Keyboard k2;// 标点符号键盘
  48. public boolean isnun = false;// 是否标点符号键盘
  49. public boolean isupper = false;// 是否大写
  50. private KeyboardView mKeyboardView;
  51. private Keyboard mKeyboard;
  52. private Window mWindow;
  53. private View mDecorView;
  54. private View mContentView;
  55. private PopupWindow mKeyboardWindow;
  56. private boolean needcustomkeyboard = true; // 是否启用自定义键盘
  57. private boolean randomkeys = false; // 数字按键是否随机
  58. private int scrolldis = 50; // 输入框在键盘被弹出时,要被推上去的距离
  59. public static int screenw = -1;// 未知宽高
  60. public static int screenh = -1;
  61. public static int screenh_nonavbar = -1; // 不包含导航栏的高度
  62. public static int real_scontenth = -1; // 实际内容高度, 计算公式:屏幕高度-导航栏高度-电量栏高度
  63. public static float density = 1.0f;
  64. public static int densityDpi = 160;
  65. /**
  66. * @param context
  67. * @param attrs
  68. */
  69. public MyKeyboard(Context context, AttributeSet attrs) {
  70. super(context, attrs);
  71. initAttributes(context);
  72. initKeyboard(context, attrs);
  73. // TODO Auto-generated constructor stub
  74. }
  75. /**
  76. * @param context
  77. * @param attrs
  78. * @param defStyle
  79. */
  80. public MyKeyboard(Context context, AttributeSet attrs, int defStyle) {
  81. super(context, attrs, defStyle);
  82. initAttributes(context);
  83. initKeyboard(context, attrs);
  84. // TODO Auto-generated constructor stub
  85. }
  86. //键盘初始化
  87. private void initKeyboard(Context context, AttributeSet attrs) {
  88. TypedArray a = context.obtainStyledAttributes(attrs,
  89. R.styleable.keyboard);
  90. if (a.hasValue(R.styleable.keyboard_xml)) {
  91. needcustomkeyboard = true;
  92. int xmlid = a.getResourceId(R.styleable.keyboard_xml, 0);
  93. mKeyboard = new Keyboard(context, xmlid);
  94. <span style="color:#ff0000;"><strong>mKeyboardView = (KeyboardView) LayoutInflater.from(context)
  95. .inflate(R.layout.mykeyboardview, null);  //加载键盘布局</strong></span>
  96. if (a.hasValue(R.styleable.keyboard_randomkeys)) {
  97. boolean random = a.getBoolean(R.styleable.keyboard_randomkeys,
  98. false);
  99. randomkeys = random;
  100. if (random) {
  101. randomdigkey(mKeyboard);
  102. }
  103. }
  104. <span style="color:#ff0000;"><strong>//使用popupwindow在下方弹出键盘,设置弹出和隐藏的动画效果</strong></span>
  105. mKeyboardView.setKeyboard(mKeyboard);
  106. mKeyboardView.setEnabled(true);
  107. mKeyboardView.setPreviewEnabled(false);
  108. mKeyboardView.setOnKeyboardActionListener(this);
  109. mKeyboardWindow = new PopupWindow(mKeyboardView,
  110. ViewGroup.LayoutParams.MATCH_PARENT,
  111. ViewGroup.LayoutParams.WRAP_CONTENT);
  112. <strong><span style="color:#ff0000;">mKeyboardWindow.setAnimationStyle(R.style.AnimationFade);//设置动画效果,文件在资源里面,这里就不贴出来。</span></strong>
  113. // mKeyboardWindow.setBackgroundDrawable(new BitmapDrawable());
  114. // mKeyboardWindow.setOutsideTouchable(true);
  115. mKeyboardWindow.setOnDismissListener(new OnDismissListener() {
  116. @Override
  117. public void onDismiss() {
  118. // TODO Auto-generated method stub
  119. if (scrolldis > 0) {
  120. int temp = scrolldis;
  121. scrolldis = 0;
  122. if (null != mContentView) {
  123. <span style="font-size:24px;color:#ff0000;"><strong>mContentView.scrollBy(0, -temp);//使布局整体向上顶的关键代码,使用布局的scrollBy重新滚动位置。</strong></span>
  124. }
  125. }
  126. }
  127. });
  128. } else {
  129. needcustomkeyboard = false;
  130. }
  131. a.recycle();
  132. }
  133. //显示键盘,
  134. private void showKeyboard() {
  135. if (null != mKeyboardWindow) {
  136. if (!mKeyboardWindow.isShowing()) {
  137. if (randomkeys) {
  138. randomdigkey(mKeyboard);
  139. }
  140. mKeyboardView.setKeyboard(mKeyboard);
  141. mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.BOTTOM,
  142. 0, 0);
  143. mKeyboardWindow.update();
  144. if (null != mDecorView && null != mContentView) {
  145. int[] pos = new int[2];
  146. // 计算弹出的键盘的尺寸
  147. getLocationOnScreen(pos);
  148. float height = dpToPx(getContext(), 240);
  149. // int []hsmlpos=new int[2];
  150. // mDecorView.getLocationOnScreen(hsmlpos);
  151. Rect outRect = new Rect();
  152. // 然后该View有个getWindowVisibleDisplayFrame()方法可以获取到程序显示的区域,
  153. // * 包括标题栏,但不包括状态栏。
  154. mDecorView.getWindowVisibleDisplayFrame(outRect);// 获得view空间,也就是除掉标题栏
  155. // outRect.top表示状态栏(通知栏)
  156. int screen = real_scontenth;
  157. scrolldis = (int) ((pos[1] + getMeasuredHeight() - outRect.top) - (screen - height));
  158. if (scrolldis > 0) {
  159. mContentView.scrollBy(0, scrolldis);
  160. }
  161. }
  162. }
  163. }
  164. }
  165. //隐藏键盘
  166. private void hideKeyboard() {
  167. if (null != mKeyboardWindow) {
  168. if (mKeyboardWindow.isShowing()) {
  169. mKeyboardWindow.dismiss();
  170. }
  171. }
  172. }
  173. //隐藏系统的软键盘
  174. private void hideSysInput() {
  175. if (this.getWindowToken() != null) {
  176. InputMethodManager imm = (InputMethodManager) getContext()
  177. .getSystemService(Context.INPUT_METHOD_SERVICE);
  178. imm.hideSoftInputFromWindow(this.getWindowToken(),
  179. InputMethodManager.HIDE_NOT_ALWAYS);
  180. }
  181. }
  182. //edittext点击的监听事件,当点击了edittext则弹出键盘
  183. @Override
  184. public boolean onTouchEvent(MotionEvent event) {
  185. super.onTouchEvent(event);
  186. requestFocus();
  187. requestFocusFromTouch();
  188. if (needcustomkeyboard) {
  189. hideSysInput();
  190. showKeyboard();
  191. }
  192. return true;
  193. }
[java] view plaincopy print?
  1. //当点击手机的返回键,则隐藏键盘
  2. @Override
  3. public boolean onKeyDown(int keyCode, KeyEvent event) {
  4. if (keyCode == KeyEvent.KEYCODE_BACK) {
  5. if (null != mKeyboardWindow) {
  6. if (mKeyboardWindow.isShowing()) {
  7. mKeyboardWindow.dismiss();
  8. return true;
  9. }
  10. }
  11. }
  12. return super.onKeyDown(keyCode, event);
  13. }
  14. @Override
  15. public void onAttachedToWindow() {
  16. super.onAttachedToWindow();
  17. this.mWindow = ((Activity) getContext()).getWindow();
  18. this.mDecorView = this.mWindow.getDecorView();
  19. this.mContentView = this.mWindow
  20. .findViewById(Window.ID_ANDROID_CONTENT);
  21. hideSysInput();
  22. }
  23. @Override
  24. public void onDetachedFromWindow() {
  25. super.onDetachedFromWindow();
  26. hideKeyboard();
  27. mKeyboardWindow = null;
  28. mKeyboardView = null;
  29. mKeyboard = null;
  30. mDecorView = null;
  31. mContentView = null;
  32. mWindow = null;
  33. }
  34. @Override
  35. public void onPress(int primaryCode) {
  36. // TODO Auto-generated method stub
  37. }
  38. @Override
  39. public void onRelease(int primaryCode) {
  40. // TODO Auto-generated method stub
  41. }
  42. <span style="font-size:18px;color:#ff0000;"><strong>//自定义键盘每个按键的监听方法,必须实现,实现大小写切换、字母键盘和标点符号键盘之间的切换功能
  43. @Override
  44. public void onKey(int primaryCode, int[] keyCodes) {
  45. // TODO Auto-generated method stub
  46. Editable editable = this.getText();
  47. int start = this.getSelectionStart();
  48. if (primaryCode == Keyboard.KEYCODE_CANCEL) {// 隐藏键盘
  49. hideKeyboard();
  50. } else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
  51. if (editable != null && editable.length() > 0) {
  52. if (start > 0) {
  53. editable.delete(start - 1, start);
  54. }
  55. }
  56. } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小写切换
  57. changeKey();
  58. mKeyboardView.setKeyboard(k1);
  59. }
  60. else if (primaryCode == Keyboard.KEYCODE_DONE) {// 标点符号键盘切换
  61. if (isnun) {
  62. isnun = false;
  63. mKeyboardView.setKeyboard(k1);
  64. } else {
  65. isnun = true;
  66. mKeyboardView.setKeyboard(k2);
  67. }
  68. }
  69. else if (primaryCode == -110) {
  70. editable.insert(start, "00");
  71. } else if (primaryCode == -20000) {
  72. editable.insert(start, "200,000");
  73. } else if (primaryCode == -50000) {
  74. editable.insert(start, "5,000,000");
  75. } else if (primaryCode == -10000) {
  76. editable.insert(start, "10,000,000");
  77. } else if (0x0 <= primaryCode && primaryCode <= 0x7f) {
  78. // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码
  79. editable.insert(start, Character.toString((char) primaryCode));
  80. } else if (primaryCode > 0x7f) {
  81. Key mkey = getKeyByKeyCode(primaryCode);
  82. // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码
  83. editable.insert(start, mkey.label);
  84. } else {
  85. // 其他一些暂未开放的键指令,如next到下一个输入框等指令
  86. }
  87. }
  88. lt;/strong></span>
  89. /**
  90. * 键盘大小写切换
  91. */
  92. private void changeKey() {
  93. List<Key> keylist = k1.getKeys();
  94. if (isupper) {// 大写切换小写
  95. isupper = false;
  96. for (Key key : keylist) {
  97. if (key.label != null && isword(key.label.toString())) {
  98. key.label = key.label.toString().toLowerCase();
  99. key.codes[0] = key.codes[0] + 32;
  100. }
  101. }
  102. } else {// 小写切换大写
  103. isupper = true;
  104. for (Key key : keylist) {
  105. if (key.label != null && isword(key.label.toString())) {
  106. key.label = key.label.toString().toUpperCase();
  107. key.codes[0] = key.codes[0] - 32;
  108. }
  109. }
  110. }
  111. }
  112. //判断是否为字母
  113. private boolean isword(String str) {
  114. String wordstr = "abcdefghijklmnopqrstuvwxyz";
  115. if (wordstr.indexOf(str.toLowerCase()) > -1) {
  116. return true;
  117. }
  118. return false;
  119. }
  120. private Key getKeyByKeyCode(int keyCode) {
  121. if (null != mKeyboard) {
  122. List<Key> mKeys = mKeyboard.getKeys();
  123. for (int i = 0, size = mKeys.size(); i < size; i++) {
  124. Key mKey = mKeys.get(i);
  125. int codes[] = mKey.codes;
  126. if (codes[0] == keyCode) {
  127. return mKey;
  128. }
  129. }
  130. }
  131. return null;
  132. }
  133. private void initAttributes(Context context) {
  134. k1 = new Keyboard(context, R.xml.qwerty);
  135. k2 = new Keyboard(context, R.xml.qwerty2);
  136. initScreenParams(context);
  137. this.setLongClickable(false);
  138. this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
  139. removeCopyAbility();
  140. if (this.getText() != null) {
  141. this.setSelection(this.getText().length());
  142. }
  143. this.setOnFocusChangeListener(new OnFocusChangeListener() {
  144. @Override
  145. public void onFocusChange(View v, boolean hasFocus) {
  146. // TODO Auto-generated method stub
  147. if (!hasFocus) {
  148. hideKeyboard();
  149. }
  150. }
  151. });
  152. }
  153. @TargetApi(11)
  154. private void removeCopyAbility() {
  155. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
  156. this.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
  157. @Override
  158. public boolean onCreateActionMode(ActionMode mode, Menu menu) {
  159. return false;
  160. }
  161. @Override
  162. public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
  163. return false;
  164. }
  165. @Override
  166. public void onDestroyActionMode(ActionMode mode) {
  167. }
  168. @Override
  169. public boolean onActionItemClicked(ActionMode mode,
  170. MenuItem item) {
  171. return false;
  172. }
  173. });
  174. }
  175. }
  176. private boolean isNumber(String str) {
  177. String wordstr = "0123456789";
  178. if (wordstr.indexOf(str) > -1) {
  179. return true;
  180. }
  181. return false;
  182. }
  183. // 暂时未使用到,为了实现随机键盘布局
  184. private void randomdigkey(Keyboard mKeyboard) {
  185. if (mKeyboard == null) {
  186. return;
  187. }
  188. List<Key> keyList = mKeyboard.getKeys();
  189. // 查找出0-9的数字键
  190. List<Key> newkeyList = new ArrayList<Key>();
  191. for (int i = 0, size = keyList.size(); i < size; i++) {
  192. Key key = keyList.get(i);
  193. CharSequence label = key.label;
  194. if (label != null && isNumber(label.toString())) {
  195. newkeyList.add(key);
  196. }
  197. }
  198. int count = newkeyList.size();
  199. List<KeyModel> resultList = new ArrayList<KeyModel>();
  200. LinkedList<KeyModel> temp = new LinkedList<KeyModel>();
  201. for (int i = 0; i < count; i++) {
  202. temp.add(new KeyModel(48 + i, i + ""));
  203. }
  204. Random rand = new SecureRandom();
  205. rand.setSeed(SystemClock.currentThreadTimeMillis());
  206. for (int i = 0; i < count; i++) {
  207. int num = rand.nextInt(count - i);
  208. KeyModel model = temp.get(num);
  209. resultList.add(new KeyModel(model.getCode(), model.getLable()));
  210. temp.remove(num);
  211. }
  212. for (int i = 0, size = newkeyList.size(); i < size; i++) {
  213. Key newKey = newkeyList.get(i);
  214. KeyModel resultmodle = resultList.get(i);
  215. newKey.label = resultmodle.getLable();
  216. newKey.codes[0] = resultmodle.getCode();
  217. }
  218. }
  219. class KeyModel {
  220. private Integer code;
  221. private String label;
  222. public KeyModel(Integer code, String lable) {
  223. this.code = code;
  224. this.label = lable;
  225. }
  226. public Integer getCode() {
  227. return code;
  228. }
  229. public void setCode(Integer code) {
  230. this.code = code;
  231. }
  232. public String getLable() {
  233. return label;
  234. }
  235. public void setLabel(String lable) {
  236. this.label = lable;
  237. }
  238. }
  239. /**
  240. * 密度转换为像素值
  241. *
  242. * @param dp
  243. * @return
  244. */
  245. public static int dpToPx(Context context, float dp) {
  246. final float scale = context.getResources().getDisplayMetrics().density;
  247. return (int) (dp * scale + 0.5f);
  248. }
  249. private void initScreenParams(Context context) {
  250. DisplayMetrics dMetrics = new DisplayMetrics();
  251. WindowManager windowManager = (WindowManager) context
  252. .getSystemService(Context.WINDOW_SERVICE);
  253. Display display = windowManager.getDefaultDisplay();
  254. display.getMetrics(dMetrics);
  255. screenw = dMetrics.widthPixels;
  256. screenh = dMetrics.heightPixels;
  257. density = dMetrics.density;
  258. densityDpi = dMetrics.densityDpi;
  259. screenh_nonavbar = screenh;
  260. int ver = Build.VERSION.SDK_INT;
  261. // 新版本的android 系统有导航栏,造成无法正确获取高度
  262. if (ver == 13) {
  263. try {
  264. Method mt = display.getClass().getMethod("getRealHeight");
  265. screenh_nonavbar = (Integer) mt.invoke(display);
  266. } catch (Exception e) {
  267. }
  268. } else if (ver > 13) {
  269. try {
  270. Method mt = display.getClass().getMethod("getRawHeight");
  271. screenh_nonavbar = (Integer) mt.invoke(display);
  272. } catch (Exception e) {
  273. }
  274. }
  275. real_scontenth = screenh_nonavbar - getStatusBarHeight(context);
  276. }
  277. /**
  278. * 电量栏高度
  279. *
  280. * @return
  281. */
  282. public static int getStatusBarHeight(Context context) {
  283. Class<?> c = null;
  284. Object obj = null;
  285. Field field = null;
  286. int x = 0, sbar = 0;
  287. try {
  288. c = Class.forName("com.android.internal.R$dimen");
  289. obj = c.newInstance();
  290. field = c.getField("status_bar_height");
  291. x = Integer.parseInt(field.get(obj).toString());
  292. sbar = context.getResources().getDimensionPixelSize(x);
  293. } catch (Exception e1) {
  294. e1.printStackTrace();
  295. }
  296. return sbar;
  297. }

以上的文件已经解释的相当详细了,要完整的代码请转移到至此: android自定义键盘 ,关于其他的一些在布局自定义属性、和弹出和隐藏的效果知识,我就不讲解了,网上有相当多的资源,有问题欢迎指教,一直在分享自己解决每个实际问题的方法,请大家关注我,多多评论我的博文,让我们共同进步。其实这个向上顶的功能是开源中国的一位前辈的代码,链接如下: 开源中国自定义键盘 ,非常感谢,有些代码还没有看懂,特别是计算屏幕大小、键盘大小、重新定位布局文件位置的,这些关键代码希望有人能够解释一下,在他的基础上我加了自己的东西和理解,再次感谢,希望让更多遇到同样的自定义键盘在困扰的同事和后面的新手,少走弯路,不要重复造轮子,我一直觉得是这样,“拿来主义'加上自己的创新,再次分享,让整个android开发环境变得更自由,更开放,我会持续分享在实际项目中遇到问题的解决方案,有需要资源的可以联系我。

有时候真的很感谢网络上的这些前辈,基本上一开始的解决方案和思路,都得益于这些前辈,特别是csdn、安卓巴士、eoe、开源中国等这些专业的程序员网站,是这些网站的很多资源让我认识到一个个知识点,最终能够运用到自己实际的项目中来。

—————————————————————————————分割线2015年9月21日10:42:48——————————————————

增加随机生成26个字母和标题符号功能:

// 随机字母
private void randomalpkey(Keyboard mKeyboard) {
List<Key> keyList = mKeyboard.getKeys();
// 查找出a-z的数字键
List<Key> newkeyList = new ArrayList<Key>();
for (int i = 0; i < keyList.size(); i++) {
if (keyList.get(i).label != null
&& isword(keyList.get(i).label.toString())) {
newkeyList.add(keyList.get(i));
}
}
// 数组长度
int count = newkeyList.size();
// 结果集
List<KeyModel> resultList = new ArrayList<KeyModel>();
// 用一个LinkedList作为中介
LinkedList<KeyModel> temp = new LinkedList<KeyModel>();
// 初始化temp
for (int i = 0; i < count - 1; i++) {
temp.add(new KeyModel(97 + i, "" + (char) (97 + i)));
}
temp.add(new KeyModel(64, "" + (char) 64));// .
// 取数
Random rand = new Random();
for (int i = 0; i < count; i++) {
int num = rand.nextInt(count - i);
resultList.add(new KeyModel(temp.get(num).getCode(), temp.get(num)
.getLable()));
temp.remove(num);
}
for (int i = 0; i < newkeyList.size(); i++) {
newkeyList.get(i).label = resultList.get(i).getLable();
newkeyList.get(i).codes[0] = resultList.get(i).getCode();
}

mKeyboardView.setKeyboard(mKeyboard);
}

/**
* 标点符号键盘-随机
*/
private void randomInterpunctionkey(Keyboard mKeyboard) {
List<Key> keyList = mKeyboard.getKeys();

// 查找出标点符号的数字键
List<Key> newkeyList = new ArrayList<Key>();
for (int i = 0; i < keyList.size(); i++) {
if (keyList.get(i).label != null
&& isInterpunction(keyList.get(i).label.toString())) {
newkeyList.add(keyList.get(i));
}
}
// 数组长度
int count = newkeyList.size();
// 结果集
List<KeyModel> resultList = new ArrayList<KeyModel>();
// 用一个LinkedList作为中介
LinkedList<KeyModel> temp = new LinkedList<KeyModel>();

// 初始化temp
temp.add(new KeyModel(33, "" + (char) 33));
temp.add(new KeyModel(34, "" + (char) 34));
temp.add(new KeyModel(35, "" + (char) 35));
temp.add(new KeyModel(36, "" + (char) 36));
temp.add(new KeyModel(37, "" + (char) 37));
temp.add(new KeyModel(38, "" + (char) 38));
temp.add(new KeyModel(39, "" + (char) 39));
temp.add(new KeyModel(40, "" + (char) 40));
temp.add(new KeyModel(41, "" + (char) 41));
temp.add(new KeyModel(42, "" + (char) 42));
temp.add(new KeyModel(43, "" + (char) 43));
temp.add(new KeyModel(45, "" + (char) 45));
temp.add(new KeyModel(47, "" + (char) 47));
temp.add(new KeyModel(58, "" + (char) 58));
temp.add(new KeyModel(59, "" + (char) 59));
temp.add(new KeyModel(60, "" + (char) 60));
temp.add(new KeyModel(61, "" + (char) 61));
temp.add(new KeyModel(62, "" + (char) 62));
temp.add(new KeyModel(63, "" + (char) 63));
temp.add(new KeyModel(91, "" + (char) 91));
temp.add(new KeyModel(92, "" + (char) 92));
temp.add(new KeyModel(93, "" + (char) 93));
temp.add(new KeyModel(94, "" + (char) 94));
temp.add(new KeyModel(95, "" + (char) 95));
temp.add(new KeyModel(96, "" + (char) 96));
temp.add(new KeyModel(123, "" + (char) 123));
temp.add(new KeyModel(124, "" + (char) 124));
temp.add(new KeyModel(125, "" + (char) 125));
temp.add(new KeyModel(126, "" + (char) 126));

// 取数
Random rand = new Random();
for (int i = 0; i < count; i++) {
int num = rand.nextInt(count - i);
resultList.add(new KeyModel(temp.get(num).getCode(), temp.get(num)
.getLable()));
temp.remove(num);
}
for (int i = 0; i < newkeyList.size(); i++) {
newkeyList.get(i).label = resultList.get(i).getLable();
newkeyList.get(i).codes[0] = resultList.get(i).getCode();
}

mKeyboardView.setKeyboard(mKeyboard);
}

——————————————————————————————分割线  向上顶布局主类修改2015年10月15日13:44:59————————————

[java] view plaincopy print?
  1. package client.verbank.mtp.allone.util;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.Method;
  4. import java.security.SecureRandom;
  5. import java.util.ArrayList;
  6. import java.util.LinkedList;
  7. import java.util.List;
  8. import java.util.Random;
  9. import android.annotation.TargetApi;
  10. import android.app.Activity;
  11. import android.content.Context;
  12. import android.content.res.TypedArray;
  13. import android.graphics.Rect;
  14. import android.inputmethodservice.Keyboard;
  15. import android.inputmethodservice.Keyboard.Key;
  16. import android.inputmethodservice.KeyboardView;
  17. import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
  18. import android.os.Build;
  19. import android.os.SystemClock;
  20. import android.text.Editable;
  21. import android.util.AttributeSet;
  22. import android.util.DisplayMetrics;
  23. import android.view.ActionMode;
  24. import android.view.Display;
  25. import android.view.Gravity;
  26. import android.view.KeyEvent;
  27. import android.view.LayoutInflater;
  28. import android.view.Menu;
  29. import android.view.MenuItem;
  30. import android.view.MotionEvent;
  31. import android.view.View;
  32. import android.view.ViewGroup;
  33. import android.view.Window;
  34. import android.view.WindowManager;
  35. import android.view.inputmethod.EditorInfo;
  36. import android.view.inputmethod.InputMethodManager;
  37. import android.widget.EditText;
  38. import android.widget.PopupWindow;
  39. import android.widget.PopupWindow.OnDismissListener;
  40. import client.verbank.mtp.allone.R;
  41. import client.verbank.mtp.allone.consts.ISystemCommData;
  42. /**
  43. * 数字键盘(修改bug,金額輸入 .36 應該自動變成 0.36)
  44. *
  45. * @Project: FEIB_AndroidStation
  46. * @Title: MyKeyboardDigital.java
  47. * @Package client.verbank.mtp.allone.util
  48. * @Description: TODO
  49. * @author qiulinhe qiu.linhe@allone.cn
  50. * @date 2015年10月14日 上午11:04:48
  51. * @Copyright: 2015 www.allone.cn Inc. All rights reserved.
  52. * @version V3.0.0
  53. */
  54. public class MyKeyboardDigital extends EditText implements
  55. OnKeyboardActionListener, ISystemCommData {
  56. private Keyboard k1;// 字母键盘
  57. private Keyboard k2;// 标点符号键盘
  58. private Keyboard k3;// 数字键盘
  59. public boolean isnun = false;// 是否标点符号键盘
  60. public boolean isupper = false;// 是否大写
  61. private KeyboardView mKeyboardView;
  62. private Keyboard mKeyboard;
  63. private Window mWindow;
  64. private View mDecorView;
  65. private View mContentView;
  66. private PopupWindow mKeyboardWindow;
  67. private boolean needcustomkeyboard = true; // 是否启用自定义键盘
  68. private boolean randomkeys = false; // 数字按键是否随机
  69. private int scrolldis = 450; // 输入框在键盘被弹出时,要被推上去的距离
  70. public static int screenw = -1;// 未知宽高
  71. public static int screenh = -1;
  72. public static int screenh_nonavbar = -1; // 不包含导航栏的高度
  73. public static int real_scontenth = -1; // 实际内容高度, 计算公式:屏幕高度-导航栏高度-电量栏高度
  74. public static float density = 1.0f;
  75. public static int densityDpi = 160;
  76. // 接收用户在系统设定界面的自定义金额
  77. String selfdig20 = "200,000";
  78. String orgindi20 = "200,000";
  79. // 接收用户在系统设定界面的自定义金额
  80. String selfdig50 = "500,000";
  81. String orgindi50 = "500,000";
  82. // 接收用户在系统设定界面的自定义金额
  83. String selfdig100 = "10,000,000";
  84. String orgindi100 = "10,000,000";
  85. /**
  86. * @param context
  87. *
  88. * @param attrs
  89. */
  90. public MyKeyboardDigital(Context context, AttributeSet attrs) {
  91. super(context, attrs);
  92. initAttributes(context);
  93. initKeyboard(context, attrs);
  94. // TODO Auto-generated constructor stub
  95. }
  96. /**
  97. * @param context
  98. * @param attrs
  99. * @param defStyle
  100. */
  101. public MyKeyboardDigital(Context context, AttributeSet attrs, int defStyle) {
  102. super(context, attrs, defStyle);
  103. selfdig20 = SharepreferencesUtilSystemSettings.getValue(getContext(),
  104. System_key_SelfAmout2, "200,000");
  105. selfdig50 = SharepreferencesUtilSystemSettings.getValue(getContext(),
  106. System_key_SelfAmout5, "500,000");
  107. selfdig100 = SharepreferencesUtilSystemSettings.getValue(getContext(),
  108. System_key_SelfAmout10, "10,000,000");
  109. initAttributes(context);
  110. initKeyboard(context, attrs);
  111. // TODO Auto-generated constructor stub
  112. }
  113. private void initKeyboard(Context context, AttributeSet attrs) {
  114. selfdig20 = SharepreferencesUtilSystemSettings.getValue(getContext(),
  115. System_key_SelfAmout2, "200,000");
  116. selfdig50 = SharepreferencesUtilSystemSettings.getValue(getContext(),
  117. System_key_SelfAmout5, "500,000");
  118. selfdig100 = SharepreferencesUtilSystemSettings.getValue(getContext(),
  119. System_key_SelfAmout10, "10,000,000");
  120. TypedArray a = context.obtainStyledAttributes(attrs,
  121. R.styleable.keyboard);
  122. if (a.hasValue(R.styleable.keyboard_xml)) {
  123. needcustomkeyboard = true;
  124. int xmlid = a.getResourceId(R.styleable.keyboard_xml, 0);
  125. mKeyboard = new Keyboard(context, xmlid);
  126. mKeyboardView = (KeyboardView) LayoutInflater.from(context)
  127. .inflate(R.layout.mykeyboardviewdigit, null);
  128. if (a.hasValue(R.styleable.keyboard_randomkeys)) {
  129. boolean random = a.getBoolean(R.styleable.keyboard_randomkeys,
  130. false);
  131. randomkeys = random;
  132. if (random) {
  133. randomdigkey(mKeyboard);
  134. }
  135. }
  136. selfdig20 = SharepreferencesUtilSystemSettings.getValue(
  137. getContext(), System_key_SelfAmout2, "200,000");
  138. selfdig50 = SharepreferencesUtilSystemSettings.getValue(
  139. getContext(), System_key_SelfAmout5, "500,000");
  140. selfdig100 = SharepreferencesUtilSystemSettings.getValue(
  141. getContext(), System_key_SelfAmout10, "10,000,000");
  142. selfdigkey();
  143. // mKeyboardView.setKeyboard(mKeyboard);
  144. mKeyboardView.setEnabled(true);
  145. mKeyboardView.setPreviewEnabled(false);
  146. mKeyboardView.setOnKeyboardActionListener(this);
  147. mKeyboardWindow = new PopupWindow(mKeyboardView,
  148. ViewGroup.LayoutParams.MATCH_PARENT,
  149. ViewGroup.LayoutParams.WRAP_CONTENT);
  150. mKeyboardWindow.setAnimationStyle(R.style.AnimationFade);
  151. // mKeyboardWindow.setBackgroundDrawable(new BitmapDrawable());
  152. // mKeyboardWindow.setOutsideTouchable(true);
  153. mKeyboardWindow.setOnDismissListener(new OnDismissListener() {
  154. @Override
  155. public void onDismiss() {
  156. // TODO Auto-generated method stub
  157. if (scrolldis > 0) {
  158. int temp = scrolldis;
  159. // scrolldis = 0;
  160. if (null != mContentView) {
  161. mContentView.scrollBy(0, -temp);
  162. }
  163. }
  164. }
  165. });
  166. } else {
  167. needcustomkeyboard = false;
  168. }
  169. a.recycle();
  170. }
  171. private void showKeyboard() {
  172. if (null != mKeyboardWindow) {
  173. if (!mKeyboardWindow.isShowing()) {
  174. if (randomkeys) {
  175. randomdigkey(mKeyboard);
  176. }
  177. selfdig20 = SharepreferencesUtilSystemSettings.getValue(
  178. getContext(), System_key_SelfAmout2, "200,000");
  179. selfdig50 = SharepreferencesUtilSystemSettings.getValue(
  180. getContext(), System_key_SelfAmout5, "500,000");
  181. selfdig100 = SharepreferencesUtilSystemSettings.getValue(
  182. getContext(), System_key_SelfAmout10, "10,000,000");
  183. selfdigkey();
  184. // mKeyboardView.setKeyboard(mKeyboard);
  185. mKeyboardWindow.setAnimationStyle(R.style.AnimBottom);
  186. mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.RIGHT
  187. | Gravity.BOTTOM, 0, 0);
  188. mKeyboardWindow.update();
  189. if (null != mDecorView && null != mContentView) {
  190. int[] pos = new int[2];
  191. // 计算弹出的键盘的尺寸
  192. getLocationOnScreen(pos);
  193. float height = dpToPx(getContext(), 240);
  194. // int []hsmlpos=new int[2];
  195. // mDecorView.getLocationOnScreen(hsmlpos);
  196. Rect outRect = new Rect();
  197. // 然后该View有个getWindowVisibleDisplayFrame()方法可以获取到程序显示的区域,
  198. // * 包括标题栏,但不包括状态栏。
  199. mDecorView.getWindowVisibleDisplayFrame(outRect);// 获得view空间,也就是除掉标题栏
  200. // outRect.top表示状态栏(通知栏)
  201. int screen = real_scontenth;
  202. // scrolldis = (int) ((pos[1] + getMeasuredHeight() -
  203. // outRect.top)
  204. // - (screen - height) + 500);
  205. if (scrolldis > 0) {
  206. mContentView.scrollBy(0, scrolldis);
  207. }
  208. }
  209. }
  210. }
  211. }
  212. private void hideKeyboard() {
  213. if (null != mKeyboardWindow) {
  214. if (mKeyboardWindow.isShowing()) {
  215. mKeyboardWindow.dismiss();
  216. }
  217. }
  218. }
  219. private void hideSysInput() {
  220. if (this.getWindowToken() != null) {
  221. InputMethodManager imm = (InputMethodManager) getContext()
  222. .getSystemService(Context.INPUT_METHOD_SERVICE);
  223. imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
  224. }
  225. }
  226. @Override
  227. public boolean onTouchEvent(MotionEvent event) {
  228. super.onTouchEvent(event);
  229. requestFocus();
  230. requestFocusFromTouch();
  231. if (needcustomkeyboard) {
  232. hideSysInput();
  233. showKeyboard();
  234. }
  235. return true;
  236. }
  237. @Override
  238. public boolean onKeyDown(int keyCode, KeyEvent event) {
  239. if (keyCode == KeyEvent.KEYCODE_BACK) {
  240. if (null != mKeyboardWindow) {
  241. if (mKeyboardWindow.isShowing()) {
  242. mKeyboardWindow.dismiss();
  243. return true;
  244. }
  245. }
  246. }
  247. return super.onKeyDown(keyCode, event);
  248. }
  249. @Override
  250. public void onAttachedToWindow() {
  251. super.onAttachedToWindow();
  252. this.mWindow = ((Activity) getContext()).getWindow();
  253. this.mDecorView = this.mWindow.getDecorView();
  254. this.mContentView = this.mWindow
  255. .findViewById(Window.ID_ANDROID_CONTENT);
  256. hideSysInput();
  257. }
  258. @Override
  259. public void onDetachedFromWindow() {
  260. super.onDetachedFromWindow();
  261. hideKeyboard();
  262. mKeyboardWindow = null;
  263. mKeyboardView = null;
  264. mKeyboard = null;
  265. mDecorView = null;
  266. mContentView = null;
  267. mWindow = null;
  268. }
  269. @Override
  270. public void onPress(int primaryCode) {
  271. // TODO Auto-generated method stub
  272. }
  273. @Override
  274. public void onRelease(int primaryCode) {
  275. // TODO Auto-generated method stub
  276. }
  277. @Override
  278. public void onKey(int primaryCode, int[] keyCodes) {
  279. // TODO Auto-generated method stub
  280. Editable editable = this.getText();
  281. int start = this.getSelectionStart();
  282. if (primaryCode == Keyboard.KEYCODE_CANCEL) {// 隐藏键盘
  283. hideKeyboard();
  284. } else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
  285. if (editable != null && editable.length() > 0) {
  286. if (start > 0) {
  287. editable.delete(start - 1, start);
  288. }
  289. }
  290. } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小写切换
  291. changeKey();
  292. mKeyboardView.setKeyboard(k1);
  293. }
  294. else if (primaryCode == Keyboard.KEYCODE_DONE) {// 标点符号键盘切换
  295. if (isnun) {
  296. isnun = false;
  297. mKeyboardView.setKeyboard(k1);
  298. } else {
  299. isnun = true;
  300. mKeyboardView.setKeyboard(k2);
  301. }
  302. } else if (primaryCode == 46) {
  303. // 当用户输入.3的时候自动转换为0.3
  304. if (editable != null && editable.length() > 0) {
  305. if (start > 0) {
  306. editable.insert(start, ".");
  307. }
  308. } else {
  309. editable.insert(start, "0.");
  310. }
  311. }
  312. else if (primaryCode == -110) {
  313. editable.insert(start, "00");
  314. } else if (primaryCode == -20000) {
  315. editable.insert(start, selfdig20);
  316. } else if (primaryCode == -50000) {
  317. editable.insert(start, selfdig50);
  318. } else if (primaryCode == -10000) {
  319. editable.insert(start, selfdig100);
  320. } else if (0x0 <= primaryCode && primaryCode <= 0x7f) {
  321. // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码
  322. editable.insert(start, Character.toString((char) primaryCode));
  323. } else if (primaryCode > 0x7f) {
  324. Key mkey = getKeyByKeyCode(primaryCode);
  325. // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码
  326. editable.insert(start, mkey.label);
  327. } else {
  328. // 其他一些暂未开放的键指令,如next到下一个输入框等指令
  329. }
  330. }
  331. // 数字键盘测试是否改变200,000和500,000让用户自定义
  332. private void selfdigkey() {
  333. if (mKeyboard == null) {
  334. return;
  335. }
  336. List<Key> keyList = k3.getKeys();
  337. // 查找出0-9的数字键
  338. for (int i = 0, size = keyList.size(); i < size; i++) {
  339. Key key = keyList.get(i);
  340. CharSequence label = key.label;
  341. // if (label != null && label.toString().equals(orgindi20)) {
  342. // keyList.get(i).label = selfdig;
  343. // orgindi20 = selfdig;
  344. // }
  345. if (label != null && label.toString().equals(orgindi20)) {
  346. keyList.get(i).label = selfdig20;
  347. keyList.get(i).codes[0] = -20000;
  348. orgindi20 = selfdig20;
  349. }
  350. if (label != null && label.toString().equals(orgindi50)) {
  351. keyList.get(i).label = selfdig50;
  352. keyList.get(i).codes[0] = -50000;
  353. orgindi50 = selfdig50;
  354. }
  355. if (label != null && label.toString().equals(orgindi100)) {
  356. keyList.get(i).label = selfdig100;
  357. keyList.get(i).codes[0] = -10000;
  358. orgindi100 = selfdig100;
  359. }
  360. }
  361. mKeyboardView.setKeyboard(k3);
  362. }
  363. /**
  364. * 键盘大小写切换
  365. */
  366. private void changeKey() {
  367. List<Key> keylist = k1.getKeys();
  368. if (isupper) {// 大写切换小写
  369. isupper = false;
  370. for (Key key : keylist) {
  371. if (key.label != null && isword(key.label.toString())) {
  372. key.label = key.label.toString().toLowerCase();
  373. key.codes[0] = key.codes[0] + 32;
  374. }
  375. }
  376. } else {// 小写切换大写
  377. isupper = true;
  378. for (Key key : keylist) {
  379. if (key.label != null && isword(key.label.toString())) {
  380. key.label = key.label.toString().toUpperCase();
  381. key.codes[0] = key.codes[0] - 32;
  382. }
  383. }
  384. }
  385. }
  386. private boolean isword(String str) {
  387. String wordstr = "abcdefghijklmnopqrstuvwxyz";
  388. if (wordstr.indexOf(str.toLowerCase()) > -1) {
  389. return true;
  390. }
  391. return false;
  392. }
  393. @Override
  394. public void onText(CharSequence text) {
  395. // TODO Auto-generated method stub
  396. }
  397. @Override
  398. public void swipeLeft() {
  399. // TODO Auto-generated method stub
  400. }
  401. @Override
  402. public void swipeRight() {
  403. // TODO Auto-generated method stub
  404. }
  405. @Override
  406. public void swipeDown() {
  407. // TODO Auto-generated method stub
  408. }
  409. @Override
  410. public void swipeUp() {
  411. // TODO Auto-generated method stub
  412. }
  413. private Key getKeyByKeyCode(int keyCode) {
  414. if (null != mKeyboard) {
  415. List<Key> mKeys = mKeyboard.getKeys();
  416. for (int i = 0, size = mKeys.size(); i < size; i++) {
  417. Key mKey = mKeys.get(i);
  418. int codes[] = mKey.codes;
  419. if (codes[0] == keyCode) {
  420. return mKey;
  421. }
  422. }
  423. }
  424. return null;
  425. }
  426. private void initAttributes(Context context) {
  427. k1 = new Keyboard(context, R.xml.qwerty);
  428. k2 = new Keyboard(context, R.xml.qwerty2);
  429. k3 = new Keyboard(context, R.xml.amountinputkeyboard);
  430. initScreenParams(context);
  431. this.setLongClickable(false);
  432. this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
  433. removeCopyAbility();
  434. if (this.getText() != null) {
  435. this.setSelection(this.getText().length());
  436. }
  437. this.setOnFocusChangeListener(new OnFocusChangeListener() {
  438. @Override
  439. public void onFocusChange(View v, boolean hasFocus) {
  440. // TODO Auto-generated method stub
  441. if (!hasFocus) {
  442. hideKeyboard();
  443. }
  444. }
  445. });
  446. }
  447. @TargetApi(11)
  448. private void removeCopyAbility() {
  449. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
  450. this.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
  451. @Override
  452. public boolean onCreateActionMode(ActionMode mode, Menu menu) {
  453. return false;
  454. }
  455. @Override
  456. public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
  457. return false;
  458. }
  459. @Override
  460. public void onDestroyActionMode(ActionMode mode) {
  461. }
  462. @Override
  463. public boolean onActionItemClicked(ActionMode mode,
  464. MenuItem item) {
  465. return false;
  466. }
  467. });
  468. }
  469. }
  470. private boolean isNumber(String str) {
  471. String wordstr = "0123456789";
  472. if (wordstr.indexOf(str) > -1) {
  473. return true;
  474. }
  475. return false;
  476. }
  477. private void randomdigkey(Keyboard mKeyboard) {
  478. if (mKeyboard == null) {
  479. return;
  480. }
  481. List<Key> keyList = mKeyboard.getKeys();
  482. // 查找出0-9的数字键
  483. List<Key> newkeyList = new ArrayList<Key>();
  484. for (int i = 0, size = keyList.size(); i < size; i++) {
  485. Key key = keyList.get(i);
  486. CharSequence label = key.label;
  487. if (label != null && isNumber(label.toString())) {
  488. newkeyList.add(key);
  489. }
  490. }
  491. int count = newkeyList.size();
  492. List<KeyModel> resultList = new ArrayList<KeyModel>();
  493. LinkedList<KeyModel> temp = new LinkedList<KeyModel>();
  494. for (int i = 0; i < count; i++) {
  495. temp.add(new KeyModel(48 + i, i + ""));
  496. }
  497. Random rand = new SecureRandom();
  498. rand.setSeed(SystemClock.currentThreadTimeMillis());
  499. for (int i = 0; i < count; i++) {
  500. int num = rand.nextInt(count - i);
  501. KeyModel model = temp.get(num);
  502. resultList.add(new KeyModel(model.getCode(), model.getLable()));
  503. temp.remove(num);
  504. }
  505. for (int i = 0, size = newkeyList.size(); i < size; i++) {
  506. Key newKey = newkeyList.get(i);
  507. KeyModel resultmodle = resultList.get(i);
  508. newKey.label = resultmodle.getLable();
  509. newKey.codes[0] = resultmodle.getCode();
  510. }
  511. }
  512. class KeyModel {
  513. private Integer code;
  514. private String label;
  515. public KeyModel(Integer code, String lable) {
  516. this.code = code;
  517. this.label = lable;
  518. }
  519. public Integer getCode() {
  520. return code;
  521. }
  522. public void setCode(Integer code) {
  523. this.code = code;
  524. }
  525. public String getLable() {
  526. return label;
  527. }
  528. public void setLabel(String lable) {
  529. this.label = lable;
  530. }
  531. }
  532. /**
  533. * 密度转换为像素值
  534. *
  535. * @param dp
  536. * @return
  537. */
  538. public static int dpToPx(Context context, float dp) {
  539. final float scale = context.getResources().getDisplayMetrics().density;
  540. return (int) (dp * scale + 0.5f);
  541. }
  542. private void initScreenParams(Context context) {
  543. DisplayMetrics dMetrics = new DisplayMetrics();
  544. WindowManager windowManager = (WindowManager) context
  545. .getSystemService(Context.WINDOW_SERVICE);
  546. Display display = windowManager.getDefaultDisplay();
  547. display.getMetrics(dMetrics);
  548. screenw = dMetrics.widthPixels;
  549. screenh = dMetrics.heightPixels;
  550. density = dMetrics.density;
  551. densityDpi = dMetrics.densityDpi;
  552. screenh_nonavbar = screenh;
  553. int ver = Build.VERSION.SDK_INT;
  554. // 新版本的android 系统有导航栏,造成无法正确获取高度
  555. if (ver == 13) {
  556. try {
  557. Method mt = display.getClass().getMethod("getRealHeight");
  558. screenh_nonavbar = (Integer) mt.invoke(display);
  559. } catch (Exception e) {
  560. }
  561. } else if (ver > 13) {
  562. try {
  563. Method mt = display.getClass().getMethod("getRawHeight");
  564. screenh_nonavbar = (Integer) mt.invoke(display);
  565. } catch (Exception e) {
  566. }
  567. }
  568. real_scontenth = screenh_nonavbar - getStatusBarHeight(context);
  569. }
  570. /**
  571. * 电量栏高度
  572. *
  573. * @return
  574. */
  575. public static int getStatusBarHeight(Context context) {
  576. Class<?> c = null;
  577. Object obj = null;
  578. Field field = null;
  579. int x = 0, sbar = 0;
  580. try {
  581. c = Class.forName("com.android.internal.R$dimen");
  582. obj = c.newInstance();
  583. field = c.getField("status_bar_height");
  584. x = Integer.parseInt(field.get(obj).toString());
  585. sbar = context.getResources().getDimensionPixelSize(x);
  586. } catch (Exception e1) {
  587. e1.printStackTrace();
  588. }
  589. return sbar;
  590. }
  591. }

================================分割线,更新时间====================================

因为上述自定义的键盘在很多手机上,向上推的高度是固定的,由于分辨率的原因,所以有些还是会挡住下面的按钮,所以我找到了一个先计算出手机的密度,再乘以一个固定的数值,然后将界面整体向上移动:

[java] view plaincopy print?
  1. DisplayMetrics dm = contextceshi.getResources()
  2. .getDisplayMetrics();
  3. int scalsize = (int) (80 * dm.density);
  4. if (scalsize > 0) {
  5. int temp = scalsize;
  6. // scrolldis = 0;
  7. if (null != mContentView) {
  8. mContentView.scrollBy(100, -temp);
  9. }
  10. }

=====================================分割线更新时间2016年3月16日11:00:11===============================================================

上述的键盘布局,你会发现第一行只有一个下拉的按键就是隐藏键盘,但这个如果有了整体背景之后,横竖的间距就有出现,这样你从美工那里拿来的图片,设置成这个按键的背景之后,就会发现无法覆盖整体的背景,所以呢,我们需要设置他的横竖屏的间距,关键是可以设置成负值,这样就能自由调整。如下代码:

[java] view plaincopy print?
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:horizontalGap="1.2px"
  4. android:keyWidth="9.89%p"
  5. android:verticalGap="2px" >
  6. <Row
  7. android:horizontalGap="-5px"
  8. android:keyHeight="28dp"
  9. android:verticalGap="2px" >
  10. <Key
  11. android:codes="-3"
  12. android:keyHeight="22dp"
  13. android:keyIcon="@drawable/keyboardblow"
  14. android:keyWidth="100%p" />
  15. </Row>

转自:http://blog.csdn.net/nihaoqiulinhe/article/details/48546265

Android 自定义键盘 随机键盘相关推荐

  1. Android 自定义安全软键盘 SafeKeyboard 开发详细说明 2.0

    Android 自定义安全软键盘 SafeKeyboard 开发详细说明 2.0 源码地址:GitHub:    https://github.com/SValence/SafeKeyboard 注意 ...

  2. Android自定义输入法软键盘

    1 功能描述 触屏设备主界面中有一个文本编辑框,底部区域固定显示一个数字键盘,键盘中除数字键外,还带有*和#键功能: 提供一个自定义的数字输入法,生成apk安装包文件,嵌入到img镜像文件中去. 2 ...

  3. android 自定义数字软键盘,Android自定义键盘的实现(数字键盘和字母键盘)

    在项目中,产品对于输入方式会有特殊的要求,需要对输入方式增加特定的限制,这就需要采用自定义键盘.本文主要讲述数字键盘和字母键盘的自定义实现. 自定义键盘的实现步骤如下: 自定义CustomKeyboa ...

  4. Android自定义记账软键盘(仿鲨鱼记账的记账功能)

    鲨鱼记账App效果: 本文实现的效果图: 本文 不是什么原理分析,属于使用工具,不再具体分析.直接贴图贴代码了 自定义软键盘的XML模版 注:android:codes的值,请参考ASCII < ...

  5. Android 自定义数字虚拟键盘

    大概两年没写文章了,有些生疏,不知如何动笔,很早以前有过转行的想法,想过考公务员,所以重心不在程序上.近期通过内推的形式入职了一家大公司(社保公积金缴全额,双休,带薪十三天年假,少加班),这么好的福利 ...

  6. android 自定义安全键盘,android 实现自定义安全键盘 且每次数字随机变换位置

    但是没有实现随机键盘 本次以该demo中的数字键盘为例 如何在每次打开键盘的时候都变换对应按键的位置 在设置自定义键盘keyboardView.setKeyboard(keyboard) 之前 随机排 ...

  7. android自定义金额输入键盘_Android 自定义输入支付密码的软键盘实例代码

    Android 自定义输入支付密码的软键盘 有项目需求需要做一个密码锁功能,还有自己的软键盘,类似与支付宝那种,这里是整理的资料,大家可以看下,如有错误,欢迎留言指正 需求:要实现类似支付宝的输入支付 ...

  8. android 自定义键盘_Android自定义输入车牌号键盘、车牌简称,数字 ,字母键盘...

    本文来自阿钟的投稿,全文阅读大约十分钟 为了便于用户快捷的输入车牌号码便需要自定义个车牌键盘,而不是使用系统的键盘输入,上效果图: 横屏效果 图片 竖屏效果 图片 一.首先我们要来分析一下需要做哪些东 ...

  9. android+模拟器皮肤,自定义android模拟器皮肤和键盘映射

    我想为Android模拟器创建自己的皮肤.我有照片购买了一些皮肤图像. 有一些额外的按钮,我需要映射,以便点击它时应该生成一个特定的事件. 在我的个性化皮肤文件夹的布局文件看起来是这样的:自定义and ...

最新文章

  1. workbench应力应变曲线_说说真应力真应变
  2. WIN7 IE8的桌面图标解决了(简单有效)
  3. python sql注入漏洞 ctf_CTF-WEB 一个登录框SQL盲注
  4. 用boost库实现traceroute小工具
  5. Jetty 服务器架构分析(中)
  6. U-Net中的skip connection
  7. GIF图形文件格式文档
  8. 十大漏洞破解网吧管理软件(1)
  9. Java游戏开发中应始终坚持的10项基本原则
  10. 澳洲7人自驾选什么车_自驾车在哪里
  11. 通过Python计算经纬度点任意角度任意距离的经纬度点
  12. 2015年8月4日工作日志--------赵鑫
  13. 孙溟㠭书法篆刻《寿》
  14. strtok、strtok_s、strtok_r 字符串分割函数
  15. 智能电网如何巡检?这个方法才是标配
  16. Redis + Lua 实现 sorted set 集合保证固定数量的数据,并保留新数据剔除旧数据
  17. windows有哪些版本
  18. 请各位大虾帮我看看,这句是什么意思?
  19. matlab一阶振型图,[工学]多自由度系统的振动响应.ppt
  20. Python小白的数学建模课-B6. 新冠疫情 SEIR 改进模型

热门文章

  1. Google 机器学习术语表
  2. windbg分析C++ EH exception
  3. Android 打电话实现两种方法
  4. 插入缺失InDel insertion deletion
  5. 理工科科研结果展示怎样让PPT高大上?
  6. 学习python的摸鱼日常
  7. 游戏3D建模入门,有哪些建模软件可以选择?
  8. 92 Three.js 使用设置bumpMap凹凸贴图创建褶皱
  9. 百度网盘怎么批量改名(包含子文件夹)
  10. [PyG] 1.如何使用GCN完成一个最基本的训练过程(含GCN实现)