之前上传的另外一个自定义键盘,并没有实现键盘弹出的时候,布局向上自动调整。(网络上所有的自定义键盘都没有添加自适应的功能,而且布局没这么好看,上一个例子资源链接为:http://download.csdn.net/detail/omayyouhappy/9111809,这个资源绝对值10分,真的全网络唯一完美的自定义定制键盘,新的资源在这里:全网唯一定制键盘(向上改变布局) ,接下来就仔细的讲讲我是如何完成自定义键盘的,我得吐槽一下,一开始为了做自定义键盘,网上的例子确实很有用,避免了重复造轮子,给了我很大的启示,也快速的知道如何使用google提供的自定义键盘类使用方法,介绍几本的键盘的情况,你可以到这篇博文来了解: 整个网络可能最完善的 Android 自定义键盘 问题汇总以及解决方案,只需要花几分钟时间,就可以制作一个几本的键盘,但这个键盘有很多缺点,是通过按钮隐藏布局的形式来隐藏键盘、有可能会出现遮挡住你所要输入的edittext情况,无法适应整个屏幕布局,这篇博文就是讲解如何解决这些问题的,那么开始吧:
自定义键盘整个过程如下:
1.第一步,根据你的需求,需要定制怎样的键盘,需要几行几列,准备好键盘按键的背景图片,键盘的尺寸,在res文件下,新建一个xml文件,下面放字母、数字、标点符号键盘的布局文件,我的需求是这样的:
可以看到上述的键盘需要美工做的图片有几张:字母和数字的按键的基本背景(需要圆角)、删除按键、切换大小写的图标、点击隐藏键盘的下拉按键,设置键盘的布局为白色就可以大致实现上述的效果。这里我在写键盘文件的时候遇到几个难点,分享如下:
A.按键之间的空隙和键盘整体高度,需要不断的调整,不可能一下子就可以布置好的,特别字母键盘里的删除键,高度是两个按键,所以需要反复调试。
B.为了解决点击下拉按钮隐藏键盘的功能:放弃原先点击下拉按钮,隐藏整个键盘的布局的方案,而改用在键盘文件中再加一整行,只有一个按键,就是done,完成按钮,这是系统定义好的完成功能,code值为: -3。(所以我们发现很多系统自动的比如切换大小写、删除功能、空格功能,都是已经定义好了code值,只需要找到对应的含义,直接定义使用就可以了。)
字母布局文件如下(主要部分,代码可以到资源里下载):res\xml\qwerty.xml
<?xml version="1.0" encoding="UTF-8"?> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:horizontalGap="1px" android:keyWidth="9.7%p" android:verticalGap="3px" > <Row android:verticalGap="18px" > <Key android:codes="-3" android:keyIcon="@drawable/ret" android:keyWidth="100%p" /> </Row> 。。。。。。。。。。。。。。。
。。。。。。。。。。。。 <Row android:keyHeight="40dp" > <Key android:codes="-1" android:keyEdgeFlags="left" android:keyIcon="@drawable/updata" android:keyWidth="9.55%p" /> <Key android:codes="-4" android:keyLabel=".?&" /> <Key android:codes="122" android:keyLabel="z" /> <Key android:codes="120" android:keyLabel="x" /> <Key android:codes="99" android:keyLabel="c" /> <Key android:codes="118" android:keyLabel="v" /> <Key android:codes="98" android:keyLabel="b" /> <Key android:codes="110" android:keyLabel="n" /> <Key android:codes="109" android:keyLabel="m" /> </Row> </Keyboard>
<?xml version="1.0" encoding="UTF-8"?> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:horizontalGap="1px" android:keyWidth="9.7%p" android:verticalGap="3px" > <Row android:verticalGap="18px"> <Key android:codes="-3" android:keyIcon="@drawable/ret" android:keyWidth="100%p" android:verticalGap="3px" /> </Row>
。。。。。。。。。。。。。。。。。。。。。。<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">。。。。。。。。。。。。。。。。。。。</span>
<Row android:keyHeight="40dp" > <Key android:codes="-1" android:isSticky="true" android:keyIcon="@drawable/updata" /> <Key android:codes="-4" android:keyLabel="abc" /> <Key android:codes="96" android:keyLabel="`" /> <Key android:codes="32" android:isRepeatable="true" android:keyLabel="space" android:keyWidth="39%p" /> <Key android:codes="46" android:keyLabel="." /> <Key android:codes="44" android:keyLabel="," /> </Row> </Keyboard>
<?xml version="1.0" encoding="utf-8"?> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:horizontalGap="3px" android:keyWidth="24.2%p" android:verticalGap="3px" > <Row android:verticalGap="18px" > <Key android:codes="-3" android:keyIcon="@drawable/ret" android:keyWidth="100%p" android:verticalGap="3px" /> </Row> 。。。。。。。。。。。。。
。。。。。。。。。。。。。 <Row android:keyHeight="50dp" > <Key android:codes="46" android:keyLabel="." /> <Key android:codes="48" android:keyLabel="0" /> <Key android:codes="-110" android:keyLabel="00" /> <Key android:codes="-5" android:isRepeatable="true" android:keyEdgeFlags="right" android:keyIcon="@drawable/deletepng" /> </Row> </Keyboard>
<Row <span style="color:#ff0000;"><strong>android:verticalGap="18px"</strong></span> > <Key android:codes="-3" android:keyIcon="@drawable/ret" android:keyWidth="100%p" android:verticalGap="3px" /> </Row>
对于键盘之间的垂直和水平方向的间距多少合适,以及每个按键占据的百分比多少合适,都要根据你所使用的手机、按键背景图片大小、有几行按键来细心调整,在这段代码进行调整:
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:horizontalGap="3px" android:keyWidth="24.2%p" android:verticalGap="3px" </strong>
2.定义好了你所需要的键盘布局,已经完成了关键性的一步,下面就是如何在点击edit之后,隐藏系统键盘,弹出自定义键盘,点击按钮隐藏键盘等功能。
第二步,建立你所需要放置自定义键盘的主布局文件,如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:mykeyboard="http://schemas.android.com/apk/res/com.example.testkeyboard" android:id="@+id/fulllayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.example.testkeyboard.MyKeyboard// 自定义<span style="font-family: Arial, Helvetica, sans-serif;">EditText,继承于EditText,实现键盘implements OnKeyboardActionListener接口 android:id="@+id/et" android:layout_width="match_parent" android:layout_height="30dp" android:layout_marginTop="10dp" android:background="@drawable/gray_shape" //设置圆角效果 android:gravity="center" android:hint="身份证号" android:singleLine="true" android:textColor="@color/black" android:textColorHint="#BABABA" mykeyboard:xml="@xml/amountinputkeyboard" /> // <com.example.testkeyboard.MyKeyboard android:id="@+id/etChar" android:layout_width="match_parent" android:layout_height="30dp" android:layout_marginTop="10dp" android:background="@drawable/gray_shape" android:gravity="center" android:hint="字母和标点符号键盘" android:singleLine="true" android:textColor="@color/black" android:textColorHint="#BABABA" mykeyboard:xml="@xml/qwerty" /> </LinearLayout>键盘单独布局文件: res\layout\mykeyboardview.xml
<?xml version="1.0" encoding="utf-8"?> android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"//系统自带的键盘布局文件 android:id="@+id/keyboard_view" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" <span style="color:#ff0000;"> android:background="@color/white" //设置键盘的整个背景为白色</span> android:focusable="true" android:focusableInTouchMode="true" android:keyBackground="@drawable/d" android:keyTextColor="#A8AAAB" android:keyTextSize="20sp" android:labelTextSize="15sp" android:padding="2.5dp" /> <!-- android:keyBackground="@drawable/data" -->该类主要是让主控制类加载。
第三步:编写主控制类:主要显示键盘和控制键盘动画隐藏弹出效果,主控制类:src\com\example\testkeyboard\MyKeyboard.java,主要代码注释如下:
package com.example.testkeyboard; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.security.SecureRandom; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Random; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.inputmethodservice.Keyboard; import android.inputmethodservice.Keyboard.Key; import android.inputmethodservice.KeyboardView; import android.inputmethodservice.KeyboardView.OnKeyboardActionListener; import android.os.Build; import android.os.SystemClock; import android.text.Editable; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.ActionMode; import android.view.Display; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; /** * * 自定义键盘,有按下效果 * */ public class MyKeyboard extends EditText implements OnKeyboardActionListener { private Keyboard k1;// 字母键盘 private Keyboard k2;// 标点符号键盘 public boolean isnun = false;// 是否标点符号键盘 public boolean isupper = false;// 是否大写 private KeyboardView mKeyboardView; private Keyboard mKeyboard; private Window mWindow; private View mDecorView; private View mContentView; private PopupWindow mKeyboardWindow; private boolean needcustomkeyboard = true; // 是否启用自定义键盘 private boolean randomkeys = false; // 数字按键是否随机 private int scrolldis = 50; // 输入框在键盘被弹出时,要被推上去的距离 public static int screenw = -1;// 未知宽高 public static int screenh = -1; public static int screenh_nonavbar = -1; // 不包含导航栏的高度 public static int real_scontenth = -1; // 实际内容高度, 计算公式:屏幕高度-导航栏高度-电量栏高度 public static float density = 1.0f; public static int densityDpi = 160; /** * @param context * @param attrs */ public MyKeyboard(Context context, AttributeSet attrs) { super(context, attrs); initAttributes(context); initKeyboard(context, attrs); // TODO Auto-generated constructor stub } /** * @param context * @param attrs * @param defStyle */ public MyKeyboard(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initAttributes(context); initKeyboard(context, attrs); // TODO Auto-generated constructor stub } //键盘初始化 private void initKeyboard(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.keyboard); if (a.hasValue(R.styleable.keyboard_xml)) { needcustomkeyboard = true; int xmlid = a.getResourceId(R.styleable.keyboard_xml, 0); mKeyboard = new Keyboard(context, xmlid); <span style="color:#ff0000;"><strong>mKeyboardView = (KeyboardView) LayoutInflater.from(context) .inflate(R.layout.mykeyboardview, null); //加载键盘布局</strong></span> if (a.hasValue(R.styleable.keyboard_randomkeys)) { boolean random = a.getBoolean(R.styleable.keyboard_randomkeys, false); randomkeys = random; if (random) { randomdigkey(mKeyboard); } } <span style="color:#ff0000;"><strong>//使用popupwindow在下方弹出键盘,设置弹出和隐藏的动画效果</strong></span> mKeyboardView.setKeyboard(mKeyboard); mKeyboardView.setEnabled(true); mKeyboardView.setPreviewEnabled(false); mKeyboardView.setOnKeyboardActionListener(this); mKeyboardWindow = new PopupWindow(mKeyboardView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); <strong><span style="color:#ff0000;">mKeyboardWindow.setAnimationStyle(R.style.AnimationFade);//设置动画效果,文件在资源里面,这里就不贴出来。</span></strong> // mKeyboardWindow.setBackgroundDrawable(new BitmapDrawable()); // mKeyboardWindow.setOutsideTouchable(true); mKeyboardWindow.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { // TODO Auto-generated method stub if (scrolldis > 0) { int temp = scrolldis; scrolldis = 0; if (null != mContentView) { <span style="font-size:24px;color:#ff0000;"><strong>mContentView.scrollBy(0, -temp);//使布局整体向上顶的关键代码,使用布局的scrollBy重新滚动位置。</strong></span> } } } }); } else { needcustomkeyboard = false; } a.recycle(); } //显示键盘, private void showKeyboard() { if (null != mKeyboardWindow) { if (!mKeyboardWindow.isShowing()) { if (randomkeys) { randomdigkey(mKeyboard); } mKeyboardView.setKeyboard(mKeyboard); mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.BOTTOM, 0, 0); mKeyboardWindow.update(); if (null != mDecorView && null != mContentView) { int[] pos = new int[2]; // 计算弹出的键盘的尺寸 getLocationOnScreen(pos); float height = dpToPx(getContext(), 240); // int []hsmlpos=new int[2]; // mDecorView.getLocationOnScreen(hsmlpos); Rect outRect = new Rect(); // 然后该View有个getWindowVisibleDisplayFrame()方法可以获取到程序显示的区域, // * 包括标题栏,但不包括状态栏。 mDecorView.getWindowVisibleDisplayFrame(outRect);// 获得view空间,也就是除掉标题栏 // outRect.top表示状态栏(通知栏) int screen = real_scontenth; scrolldis = (int) ((pos[1] + getMeasuredHeight() - outRect.top) - (screen - height)); if (scrolldis > 0) { mContentView.scrollBy(0, scrolldis); } } } } } //隐藏键盘 private void hideKeyboard() { if (null != mKeyboardWindow) { if (mKeyboardWindow.isShowing()) { mKeyboardWindow.dismiss(); } } } //隐藏系统的软键盘 private void hideSysInput() { if (this.getWindowToken() != null) { InputMethodManager imm = (InputMethodManager) getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(this.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } } //edittext点击的监听事件,当点击了edittext则弹出键盘 @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); requestFocus(); requestFocusFromTouch(); if (needcustomkeyboard) { hideSysInput(); showKeyboard(); } return true; }
//当点击手机的返回键,则隐藏键盘 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (null != mKeyboardWindow) { if (mKeyboardWindow.isShowing()) { mKeyboardWindow.dismiss(); return true; } } } return super.onKeyDown(keyCode, event); } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); this.mWindow = ((Activity) getContext()).getWindow(); this.mDecorView = this.mWindow.getDecorView(); this.mContentView = this.mWindow .findViewById(Window.ID_ANDROID_CONTENT); hideSysInput(); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); hideKeyboard(); mKeyboardWindow = null; mKeyboardView = null; mKeyboard = null; mDecorView = null; mContentView = null; mWindow = null; } @Override public void onPress(int primaryCode) { // TODO Auto-generated method stub } @Override public void onRelease(int primaryCode) { // TODO Auto-generated method stub } <span style="font-size:18px;color:#ff0000;"><strong>//自定义键盘每个按键的监听方法,必须实现,实现大小写切换、字母键盘和标点符号键盘之间的切换功能 @Override public void onKey(int primaryCode, int[] keyCodes) { // TODO Auto-generated method stub Editable editable = this.getText(); int start = this.getSelectionStart(); if (primaryCode == Keyboard.KEYCODE_CANCEL) {// 隐藏键盘 hideKeyboard(); } else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退 if (editable != null && editable.length() > 0) { if (start > 0) { editable.delete(start - 1, start); } } } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小写切换 changeKey(); mKeyboardView.setKeyboard(k1); } else if (primaryCode == Keyboard.KEYCODE_DONE) {// 标点符号键盘切换 if (isnun) { isnun = false; mKeyboardView.setKeyboard(k1); } else { isnun = true; mKeyboardView.setKeyboard(k2); } } else if (primaryCode == -110) { editable.insert(start, "00"); } else if (primaryCode == -20000) { editable.insert(start, "200,000"); } else if (primaryCode == -50000) { editable.insert(start, "5,000,000"); } else if (primaryCode == -10000) { editable.insert(start, "10,000,000"); } else if (0x0 <= primaryCode && primaryCode <= 0x7f) { // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码 editable.insert(start, Character.toString((char) primaryCode)); } else if (primaryCode > 0x7f) { Key mkey = getKeyByKeyCode(primaryCode); // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码 editable.insert(start, mkey.label); } else { // 其他一些暂未开放的键指令,如next到下一个输入框等指令 } } </strong></span> /** * 键盘大小写切换 */ private void changeKey() { List<Key> keylist = k1.getKeys(); if (isupper) {// 大写切换小写 isupper = false; for (Key key : keylist) { if (key.label != null && isword(key.label.toString())) { key.label = key.label.toString().toLowerCase(); key.codes[0] = key.codes[0] + 32; } } } else {// 小写切换大写 isupper = true; for (Key key : keylist) { if (key.label != null && isword(key.label.toString())) { key.label = key.label.toString().toUpperCase(); key.codes[0] = key.codes[0] - 32; } } } } //判断是否为字母 private boolean isword(String str) { String wordstr = "abcdefghijklmnopqrstuvwxyz"; if (wordstr.indexOf(str.toLowerCase()) > -1) { return true; } return false; } private Key getKeyByKeyCode(int keyCode) { if (null != mKeyboard) { List<Key> mKeys = mKeyboard.getKeys(); for (int i = 0, size = mKeys.size(); i < size; i++) { Key mKey = mKeys.get(i); int codes[] = mKey.codes; if (codes[0] == keyCode) { return mKey; } } } return null; } private void initAttributes(Context context) { k1 = new Keyboard(context, R.xml.qwerty); k2 = new Keyboard(context, R.xml.qwerty2); initScreenParams(context); this.setLongClickable(false); this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); removeCopyAbility(); if (this.getText() != null) { this.setSelection(this.getText().length()); } this.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { // TODO Auto-generated method stub if (!hasFocus) { hideKeyboard(); } } }); } @TargetApi(11) private void removeCopyAbility() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { this.setCustomSelectionActionModeCallback(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; } }); } } private boolean isNumber(String str) { String wordstr = "0123456789"; if (wordstr.indexOf(str) > -1) { return true; } return false; } // 暂时未使用到,为了实现随机键盘布局 private void randomdigkey(Keyboard mKeyboard) { if (mKeyboard == null) { return; } List<Key> keyList = mKeyboard.getKeys(); // 查找出0-9的数字键 List<Key> newkeyList = new ArrayList<Key>(); for (int i = 0, size = keyList.size(); i < size; i++) { Key key = keyList.get(i); CharSequence label = key.label; if (label != null && isNumber(label.toString())) { newkeyList.add(key); } } int count = newkeyList.size(); List<KeyModel> resultList = new ArrayList<KeyModel>(); LinkedList<KeyModel> temp = new LinkedList<KeyModel>(); for (int i = 0; i < count; i++) { temp.add(new KeyModel(48 + i, i + "")); } Random rand = new SecureRandom(); rand.setSeed(SystemClock.currentThreadTimeMillis()); for (int i = 0; i < count; i++) { int num = rand.nextInt(count - i); KeyModel model = temp.get(num); resultList.add(new KeyModel(model.getCode(), model.getLable())); temp.remove(num); } for (int i = 0, size = newkeyList.size(); i < size; i++) { Key newKey = newkeyList.get(i); KeyModel resultmodle = resultList.get(i); newKey.label = resultmodle.getLable(); newKey.codes[0] = resultmodle.getCode(); } } class KeyModel { private Integer code; private String label; public KeyModel(Integer code, String lable) { this.code = code; this.label = lable; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getLable() { return label; } public void setLabel(String lable) { this.label = lable; } } /** * 密度转换为像素值 * * @param dp * @return */ public static int dpToPx(Context context, float dp) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } private void initScreenParams(Context context) { DisplayMetrics dMetrics = new DisplayMetrics(); WindowManager windowManager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); display.getMetrics(dMetrics); screenw = dMetrics.widthPixels; screenh = dMetrics.heightPixels; density = dMetrics.density; densityDpi = dMetrics.densityDpi; screenh_nonavbar = screenh; int ver = Build.VERSION.SDK_INT; // 新版本的android 系统有导航栏,造成无法正确获取高度 if (ver == 13) { try { Method mt = display.getClass().getMethod("getRealHeight"); screenh_nonavbar = (Integer) mt.invoke(display); } catch (Exception e) { } } else if (ver > 13) { try { Method mt = display.getClass().getMethod("getRawHeight"); screenh_nonavbar = (Integer) mt.invoke(display); } catch (Exception e) { } } real_scontenth = screenh_nonavbar - getStatusBarHeight(context); } /** * 电量栏高度 * * @return */ public static int getStatusBarHeight(Context context) { Class<?> c = null; Object obj = null; Field field = null; int x = 0, sbar = 0; try { c = Class.forName("com.android.internal.R$dimen"); obj = c.newInstance(); field = c.getField("status_bar_height"); x = Integer.parseInt(field.get(obj).toString()); sbar = context.getResources().getDimensionPixelSize(x); } catch (Exception e1) { e1.printStackTrace(); } return sbar; } }
有时候真的很感谢网络上的这些前辈,基本上一开始的解决方案和思路,都得益于这些前辈,特别是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————————————
package client.verbank.mtp.allone.util; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.security.SecureRandom; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Random; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.inputmethodservice.Keyboard; import android.inputmethodservice.Keyboard.Key; import android.inputmethodservice.KeyboardView; import android.inputmethodservice.KeyboardView.OnKeyboardActionListener; import android.os.Build; import android.os.SystemClock; import android.text.Editable; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.ActionMode; import android.view.Display; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; import client.verbank.mtp.allone.R; import client.verbank.mtp.allone.consts.ISystemCommData; /** * 数字键盘(修改bug,金額輸入 .36 應該自動變成 0.36) * * @Project: FEIB_AndroidStation * @Title: MyKeyboardDigital.java * @Package client.verbank.mtp.allone.util * @Description: TODO * @author qiulinhe [email protected] * @date 2015年10月14日 上午11:04:48 * @Copyright: 2015 www.allone.cn Inc. All rights reserved. * @version V3.0.0 */ public class MyKeyboardDigital extends EditText implements OnKeyboardActionListener, ISystemCommData { private Keyboard k1;// 字母键盘 private Keyboard k2;// 标点符号键盘 private Keyboard k3;// 数字键盘 public boolean isnun = false;// 是否标点符号键盘 public boolean isupper = false;// 是否大写 private KeyboardView mKeyboardView; private Keyboard mKeyboard; private Window mWindow; private View mDecorView; private View mContentView; private PopupWindow mKeyboardWindow; private boolean needcustomkeyboard = true; // 是否启用自定义键盘 private boolean randomkeys = false; // 数字按键是否随机 private int scrolldis = 450; // 输入框在键盘被弹出时,要被推上去的距离 public static int screenw = -1;// 未知宽高 public static int screenh = -1; public static int screenh_nonavbar = -1; // 不包含导航栏的高度 public static int real_scontenth = -1; // 实际内容高度, 计算公式:屏幕高度-导航栏高度-电量栏高度 public static float density = 1.0f; public static int densityDpi = 160; // 接收用户在系统设定界面的自定义金额 String selfdig20 = "200,000"; String orgindi20 = "200,000"; // 接收用户在系统设定界面的自定义金额 String selfdig50 = "500,000"; String orgindi50 = "500,000"; // 接收用户在系统设定界面的自定义金额 String selfdig100 = "10,000,000"; String orgindi100 = "10,000,000"; /** * @param context * * @param attrs */ public MyKeyboardDigital(Context context, AttributeSet attrs) { super(context, attrs); initAttributes(context); initKeyboard(context, attrs); // TODO Auto-generated constructor stub } /** * @param context * @param attrs * @param defStyle */ public MyKeyboardDigital(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); selfdig20 = SharepreferencesUtilSystemSettings.getValue(getContext(), System_key_SelfAmout2, "200,000"); selfdig50 = SharepreferencesUtilSystemSettings.getValue(getContext(), System_key_SelfAmout5, "500,000"); selfdig100 = SharepreferencesUtilSystemSettings.getValue(getContext(), System_key_SelfAmout10, "10,000,000"); initAttributes(context); initKeyboard(context, attrs); // TODO Auto-generated constructor stub } private void initKeyboard(Context context, AttributeSet attrs) { selfdig20 = SharepreferencesUtilSystemSettings.getValue(getContext(), System_key_SelfAmout2, "200,000"); selfdig50 = SharepreferencesUtilSystemSettings.getValue(getContext(), System_key_SelfAmout5, "500,000"); selfdig100 = SharepreferencesUtilSystemSettings.getValue(getContext(), System_key_SelfAmout10, "10,000,000"); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.keyboard); if (a.hasValue(R.styleable.keyboard_xml)) { needcustomkeyboard = true; int xmlid = a.getResourceId(R.styleable.keyboard_xml, 0); mKeyboard = new Keyboard(context, xmlid); mKeyboardView = (KeyboardView) LayoutInflater.from(context) .inflate(R.layout.mykeyboardviewdigit, null); if (a.hasValue(R.styleable.keyboard_randomkeys)) { boolean random = a.getBoolean(R.styleable.keyboard_randomkeys, false); randomkeys = random; if (random) { randomdigkey(mKeyboard); } } selfdig20 = SharepreferencesUtilSystemSettings.getValue( getContext(), System_key_SelfAmout2, "200,000"); selfdig50 = SharepreferencesUtilSystemSettings.getValue( getContext(), System_key_SelfAmout5, "500,000"); selfdig100 = SharepreferencesUtilSystemSettings.getValue( getContext(), System_key_SelfAmout10, "10,000,000"); selfdigkey(); // mKeyboardView.setKeyboard(mKeyboard); mKeyboardView.setEnabled(true); mKeyboardView.setPreviewEnabled(false); mKeyboardView.setOnKeyboardActionListener(this); mKeyboardWindow = new PopupWindow(mKeyboardView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); mKeyboardWindow.setAnimationStyle(R.style.AnimationFade); // mKeyboardWindow.setBackgroundDrawable(new BitmapDrawable()); // mKeyboardWindow.setOutsideTouchable(true); mKeyboardWindow.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { // TODO Auto-generated method stub if (scrolldis > 0) { int temp = scrolldis; // scrolldis = 0; if (null != mContentView) { mContentView.scrollBy(0, -temp); } } } }); } else { needcustomkeyboard = false; } a.recycle(); } private void showKeyboard() { if (null != mKeyboardWindow) { if (!mKeyboardWindow.isShowing()) { if (randomkeys) { randomdigkey(mKeyboard); } selfdig20 = SharepreferencesUtilSystemSettings.getValue( getContext(), System_key_SelfAmout2, "200,000"); selfdig50 = SharepreferencesUtilSystemSettings.getValue( getContext(), System_key_SelfAmout5, "500,000"); selfdig100 = SharepreferencesUtilSystemSettings.getValue( getContext(), System_key_SelfAmout10, "10,000,000"); selfdigkey(); // mKeyboardView.setKeyboard(mKeyboard); mKeyboardWindow.setAnimationStyle(R.style.AnimBottom); mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.RIGHT | Gravity.BOTTOM, 0, 0); mKeyboardWindow.update(); if (null != mDecorView && null != mContentView) { int[] pos = new int[2]; // 计算弹出的键盘的尺寸 getLocationOnScreen(pos); float height = dpToPx(getContext(), 240); // int []hsmlpos=new int[2]; // mDecorView.getLocationOnScreen(hsmlpos); Rect outRect = new Rect(); // 然后该View有个getWindowVisibleDisplayFrame()方法可以获取到程序显示的区域, // * 包括标题栏,但不包括状态栏。 mDecorView.getWindowVisibleDisplayFrame(outRect);// 获得view空间,也就是除掉标题栏 // outRect.top表示状态栏(通知栏) int screen = real_scontenth; // scrolldis = (int) ((pos[1] + getMeasuredHeight() - // outRect.top) // - (screen - height) + 500); if (scrolldis > 0) { mContentView.scrollBy(0, scrolldis); } } } } } private void hideKeyboard() { if (null != mKeyboardWindow) { if (mKeyboardWindow.isShowing()) { mKeyboardWindow.dismiss(); } } } private void hideSysInput() { if (this.getWindowToken() != null) { InputMethodManager imm = (InputMethodManager) getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(this.getWindowToken(), 0); } } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); requestFocus(); requestFocusFromTouch(); if (needcustomkeyboard) { hideSysInput(); showKeyboard(); } return true; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (null != mKeyboardWindow) { if (mKeyboardWindow.isShowing()) { mKeyboardWindow.dismiss(); return true; } } } return super.onKeyDown(keyCode, event); } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); this.mWindow = ((Activity) getContext()).getWindow(); this.mDecorView = this.mWindow.getDecorView(); this.mContentView = this.mWindow .findViewById(Window.ID_ANDROID_CONTENT); hideSysInput(); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); hideKeyboard(); mKeyboardWindow = null; mKeyboardView = null; mKeyboard = null; mDecorView = null; mContentView = null; mWindow = null; } @Override public void onPress(int primaryCode) { // TODO Auto-generated method stub } @Override public void onRelease(int primaryCode) { // TODO Auto-generated method stub } @Override public void onKey(int primaryCode, int[] keyCodes) { // TODO Auto-generated method stub Editable editable = this.getText(); int start = this.getSelectionStart(); if (primaryCode == Keyboard.KEYCODE_CANCEL) {// 隐藏键盘 hideKeyboard(); } else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退 if (editable != null && editable.length() > 0) { if (start > 0) { editable.delete(start - 1, start); } } } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小写切换 changeKey(); mKeyboardView.setKeyboard(k1); } else if (primaryCode == Keyboard.KEYCODE_DONE) {// 标点符号键盘切换 if (isnun) { isnun = false; mKeyboardView.setKeyboard(k1); } else { isnun = true; mKeyboardView.setKeyboard(k2); } } else if (primaryCode == 46) { // 当用户输入.3的时候自动转换为0.3 if (editable != null && editable.length() > 0) { if (start > 0) { editable.insert(start, "."); } } else { editable.insert(start, "0."); } } else if (primaryCode == -110) { editable.insert(start, "00"); } else if (primaryCode == -20000) { editable.insert(start, selfdig20); } else if (primaryCode == -50000) { editable.insert(start, selfdig50); } else if (primaryCode == -10000) { editable.insert(start, selfdig100); } else if (0x0 <= primaryCode && primaryCode <= 0x7f) { // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码 editable.insert(start, Character.toString((char) primaryCode)); } else if (primaryCode > 0x7f) { Key mkey = getKeyByKeyCode(primaryCode); // 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的keycode值必须配置为该字符的ASCII码 editable.insert(start, mkey.label); } else { // 其他一些暂未开放的键指令,如next到下一个输入框等指令 } } // 数字键盘测试是否改变200,000和500,000让用户自定义 private void selfdigkey() { if (mKeyboard == null) { return; } List<Key> keyList = k3.getKeys(); // 查找出0-9的数字键 for (int i = 0, size = keyList.size(); i < size; i++) { Key key = keyList.get(i); CharSequence label = key.label; // if (label != null && label.toString().equals(orgindi20)) { // keyList.get(i).label = selfdig; // orgindi20 = selfdig; // } if (label != null && label.toString().equals(orgindi20)) { keyList.get(i).label = selfdig20; keyList.get(i).codes[0] = -20000; orgindi20 = selfdig20; } if (label != null && label.toString().equals(orgindi50)) { keyList.get(i).label = selfdig50; keyList.get(i).codes[0] = -50000; orgindi50 = selfdig50; } if (label != null && label.toString().equals(orgindi100)) { keyList.get(i).label = selfdig100; keyList.get(i).codes[0] = -10000; orgindi100 = selfdig100; } } mKeyboardView.setKeyboard(k3); } /** * 键盘大小写切换 */ private void changeKey() { List<Key> keylist = k1.getKeys(); if (isupper) {// 大写切换小写 isupper = false; for (Key key : keylist) { if (key.label != null && isword(key.label.toString())) { key.label = key.label.toString().toLowerCase(); key.codes[0] = key.codes[0] + 32; } } } else {// 小写切换大写 isupper = true; for (Key key : keylist) { if (key.label != null && isword(key.label.toString())) { key.label = key.label.toString().toUpperCase(); key.codes[0] = key.codes[0] - 32; } } } } private boolean isword(String str) { String wordstr = "abcdefghijklmnopqrstuvwxyz"; if (wordstr.indexOf(str.toLowerCase()) > -1) { return true; } return false; } @Override public void onText(CharSequence text) { // TODO Auto-generated method stub } @Override public void swipeLeft() { // TODO Auto-generated method stub } @Override public void swipeRight() { // TODO Auto-generated method stub } @Override public void swipeDown() { // TODO Auto-generated method stub } @Override public void swipeUp() { // TODO Auto-generated method stub } private Key getKeyByKeyCode(int keyCode) { if (null != mKeyboard) { List<Key> mKeys = mKeyboard.getKeys(); for (int i = 0, size = mKeys.size(); i < size; i++) { Key mKey = mKeys.get(i); int codes[] = mKey.codes; if (codes[0] == keyCode) { return mKey; } } } return null; } private void initAttributes(Context context) { k1 = new Keyboard(context, R.xml.qwerty); k2 = new Keyboard(context, R.xml.qwerty2); k3 = new Keyboard(context, R.xml.amountinputkeyboard); initScreenParams(context); this.setLongClickable(false); this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); removeCopyAbility(); if (this.getText() != null) { this.setSelection(this.getText().length()); } this.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { // TODO Auto-generated method stub if (!hasFocus) { hideKeyboard(); } } }); } @TargetApi(11) private void removeCopyAbility() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { this.setCustomSelectionActionModeCallback(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; } }); } } private boolean isNumber(String str) { String wordstr = "0123456789"; if (wordstr.indexOf(str) > -1) { return true; } return false; } private void randomdigkey(Keyboard mKeyboard) { if (mKeyboard == null) { return; } List<Key> keyList = mKeyboard.getKeys(); // 查找出0-9的数字键 List<Key> newkeyList = new ArrayList<Key>(); for (int i = 0, size = keyList.size(); i < size; i++) { Key key = keyList.get(i); CharSequence label = key.label; if (label != null && isNumber(label.toString())) { newkeyList.add(key); } } int count = newkeyList.size(); List<KeyModel> resultList = new ArrayList<KeyModel>(); LinkedList<KeyModel> temp = new LinkedList<KeyModel>(); for (int i = 0; i < count; i++) { temp.add(new KeyModel(48 + i, i + "")); } Random rand = new SecureRandom(); rand.setSeed(SystemClock.currentThreadTimeMillis()); for (int i = 0; i < count; i++) { int num = rand.nextInt(count - i); KeyModel model = temp.get(num); resultList.add(new KeyModel(model.getCode(), model.getLable())); temp.remove(num); } for (int i = 0, size = newkeyList.size(); i < size; i++) { Key newKey = newkeyList.get(i); KeyModel resultmodle = resultList.get(i); newKey.label = resultmodle.getLable(); newKey.codes[0] = resultmodle.getCode(); } } class KeyModel { private Integer code; private String label; public KeyModel(Integer code, String lable) { this.code = code; this.label = lable; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getLable() { return label; } public void setLabel(String lable) { this.label = lable; } } /** * 密度转换为像素值 * * @param dp * @return */ public static int dpToPx(Context context, float dp) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } private void initScreenParams(Context context) { DisplayMetrics dMetrics = new DisplayMetrics(); WindowManager windowManager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); display.getMetrics(dMetrics); screenw = dMetrics.widthPixels; screenh = dMetrics.heightPixels; density = dMetrics.density; densityDpi = dMetrics.densityDpi; screenh_nonavbar = screenh; int ver = Build.VERSION.SDK_INT; // 新版本的android 系统有导航栏,造成无法正确获取高度 if (ver == 13) { try { Method mt = display.getClass().getMethod("getRealHeight"); screenh_nonavbar = (Integer) mt.invoke(display); } catch (Exception e) { } } else if (ver > 13) { try { Method mt = display.getClass().getMethod("getRawHeight"); screenh_nonavbar = (Integer) mt.invoke(display); } catch (Exception e) { } } real_scontenth = screenh_nonavbar - getStatusBarHeight(context); } /** * 电量栏高度 * * @return */ public static int getStatusBarHeight(Context context) { Class<?> c = null; Object obj = null; Field field = null; int x = 0, sbar = 0; try { c = Class.forName("com.android.internal.R$dimen"); obj = c.newInstance(); field = c.getField("status_bar_height"); x = Integer.parseInt(field.get(obj).toString()); sbar = context.getResources().getDimensionPixelSize(x); } catch (Exception e1) { e1.printStackTrace(); } return sbar; } }
================================分割线,更新时间====================================
因为上述自定义的键盘在很多手机上,向上推的高度是固定的,由于分辨率的原因,所以有些还是会挡住下面的按钮,所以我找到了一个先计算出手机的密度,再乘以一个固定的数值,然后将界面整体向上移动:
DisplayMetrics dm = contextceshi.getResources() .getDisplayMetrics(); int scalsize = (int) (80 * dm.density); if (scalsize > 0) { int temp = scalsize; // scrolldis = 0; if (null != mContentView) { mContentView.scrollBy(100, -temp); } }
=====================================分割线更新时间2016年3月16日11:00:11===============================================================
上述的键盘布局,你会发现第一行只有一个下拉的按键就是隐藏键盘,但这个如果有了整体背景之后,横竖的间距就有出现,这样你从美工那里拿来的图片,设置成这个按键的背景之后,就会发现无法覆盖整体的背景,所以呢,我们需要设置他的横竖屏的间距,关键是可以设置成负值,这样就能自由调整。如下代码:
<?xml version="1.0" encoding="UTF-8"?> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:horizontalGap="1.2px" android:keyWidth="9.89%p" android:verticalGap="2px" > <Row android:horizontalGap="-5px" android:keyHeight="28dp" android:verticalGap="2px" > <Key android:codes="-3" android:keyHeight="22dp" android:keyIcon="@drawable/keyboardblow" android:keyWidth="100%p" /> </Row>