自定义键盘:
重写的Popupwindow,将自定义的键盘放到里面,然后屏蔽系统键盘,就能使用自定义的键盘了。
功能:
输入框弹出自定义键盘
点击屏幕或者back键,退出键盘
效果:
弹出框:
package com.risetek.nfc.ui.widget; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; import android.os.Build; import android.text.Editable; import android.text.InputType; import android.util.DisplayMetrics; import android.view.Display; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.EditText; import android.widget.PopupWindow; import com.risetek.nfc.R; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Created by kmje on 2015/2/26. * 自定义数字键盘 */ public class PopupKeyboardDialog extends PopupWindow implements PopupWindow.OnDismissListener { private Context mcontext; private int scrolldis = 0; 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; private View mContentView; private View mPopupView; private KeyboardView keyboardView; private Keyboard keyBoard; private EditText editText; public PopupKeyboardDialog(Context context) { super(context); } public PopupKeyboardDialog(Context context, EditText editText) { super(context); this.mcontext = context; this.editText = editText; initScreenParams(mcontext); //获取布局 lay_linear为移动的布局,因为有些设计不想移动标题栏的布局,而是移动其下面的布局 if (null == (mContentView = ((Activity) context).findViewById(R.id.lay_linear))) { mContentView = ((Activity) context).getWindow().getDecorView().findViewById(Window.ID_ANDROID_CONTENT); } mPopupView = LayoutInflater.from(mcontext).inflate( R.layout.dialog_popupkeyboard, null); keyBoard = new Keyboard(mcontext, R.xml.symbols_num); keyboardView = (KeyboardView) mPopupView .findViewById(R.id.keyboard_view); keyboardView.setEnabled(true); keyboardView.setKeyboard(keyBoard); keyboardView.setPreviewEnabled(false); keyboardView.setOnKeyboardActionListener(actionListener); this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); this.setFocusable(false); this.setOutsideTouchable(false); this.update(); ColorDrawable dw = new ColorDrawable(0000000000); this.setBackgroundDrawable(dw); setContentView(mPopupView); setAnimationStyle(R.style.keyboard_popup); this.setOnDismissListener(this); int[] pos = new int[2]; editText.getLocationOnScreen(pos); float height = dip2px(300); Rect outRect = new Rect(); ((Activity) mcontext).getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect); int screen = real_scontenth; scrolldis = (int) ((pos[1] + editText.getMeasuredHeight() - outRect.top) - (screen - height)) + 120; if (scrolldis > 0) { mContentView.scrollBy(0, scrolldis); } } private KeyboardView.OnKeyboardActionListener actionListener = new KeyboardView.OnKeyboardActionListener() { @Override public void swipeUp() { } @Override public void swipeRight() { } @Override public void swipeLeft() { } @Override public void swipeDown() { } @Override public void onText(CharSequence text) { } @Override public void onRelease(int primaryCode) { } @Override public void onPress(int primaryCode) { } @Override public void onKey(int primaryCode, int[] keyCodes) { int start = editText.getSelectionStart(); Editable editable = editText.getEditableText(); // 删除 if (primaryCode == Keyboard.KEYCODE_DELETE) { if (editable != null && editable.length() > 0) { if (start > 0) { editable.delete(start - 1, start); } } } // 完成 收起键盘 else if (primaryCode == -3) { PopupKeyboardDialog.this.dismiss(); } // 输入 else { // 将要输入的数字现在编辑框中 editable.insert(start, Character.toString((char) primaryCode)); } } }; 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; } private int dip2px(float dipValue) { final float scale = mcontext.getResources().getDisplayMetrics().density; return (int) (dipValue * scale + 0.5f); } private boolean isFlyme() { try { Method method = Build.class.getMethod("hasSmartBar"); return method != null; } catch (final Exception e) { return false; } } @Override public void onDismiss() { if (scrolldis > 0) { if (null != mContentView) { mContentView.scrollBy(0, -scrolldis); } } } }
public class MainActivity extends BaseActivity { private MainActivity mcontext; private EditText input; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mcontext = this; findViewById(R.id.button1).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub send("btn"); } }); input = (EditText) findViewById(R.id.et_put); // 自定义键盘 setShowKeyboardDialog(mcontext, input); } }
基类:
// 隐藏系统键盘 public void hideSoftInputMethod(EditText ed) { getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); int currentVersion = android.os.Build.VERSION.SDK_INT; String methodName = null; if (currentVersion >= 16) { // 4.2 methodName = "setShowSoftInputOnFocus"; } else if (currentVersion >= 14) { // 4.0 methodName = "setSoftInputShownOnFocus"; } if (methodName == null) { ed.setInputType(InputType.TYPE_NULL); } else { Class<EditText> cls = EditText.class; Method setShowSoftInputOnFocus; try { setShowSoftInputOnFocus = cls.getMethod(methodName, boolean.class); setShowSoftInputOnFocus.setAccessible(true); setShowSoftInputOnFocus.invoke(ed, false); } catch (NoSuchMethodException e) { ed.setInputType(InputType.TYPE_NULL); e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 调用 自定义数字键盘 * * @param mcontext * @param editText */ protected void setKeyBoardDialog(final Context mcontext, final EditText editText) { // editText.setInputType(InputType.TYPE_NULL); //解决显示光标的问题 hideSoftInputMethod(editText); editText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (null == popupWinowKeyboard || !popupWinowKeyboard.isShowing()) { hideSoftInput(); popupWinowKeyboard = new PopupKeyboardDialog(mcontext, editText); popupWinowKeyboard.showAtLocation(((Activity) mcontext) .getWindow().getDecorView(), Gravity.BOTTOM, 0, 0); } } }); editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean b) { if (b) { if (null == popupWinowKeyboard) { hideSoftInput(); popupWinowKeyboard = new PopupKeyboardDialog(mcontext, editText); popupWinowKeyboard.showAtLocation(((Activity) mcontext) .getWindow().getDecorView(), Gravity.BOTTOM, 0, 0); } } else { if (null != popupWinowKeyboard) { popupWinowKeyboard.dismiss(); popupWinowKeyboard = null; } } } }); } /** * 在触摸屏幕的事件中 关掉自定义键盘 */ protected void setInonTouchEvent() { if (null != popupWinowKeyboard) { popupWinowKeyboard.dismiss(); popupWinowKeyboard = null; } } @Override public boolean onTouchEvent(MotionEvent event) { setInonTouchEvent(); return super.onTouchEvent(event); } @Override protected void onStop() { super.onStop(); hideSoftInput(); setInonTouchEvent(); }
<?xml version="1.0" encoding="UTF-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 边线 --> <item> <shape> <solid android:color="#ffffff" /> </shape> </item> <!-- 背景 --> <item android:left="1px" android:top="1px"> <!-- 双边 android:right="1px" android:bottom="1px" --> <shape> <solid android:color="#00ff00" /> </shape> </item> </layer-list>demo
注意:
1.因为布局等考虑的是dp,而scroll移动是按像素移动,所以计算时要将dp转为px。
2.如果想让光标闪动,并且屏蔽系统键盘:
// 隐藏系统键盘 public void hideSoftInputMethod(EditText ed){ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); int currentVersion = android.os.Build.VERSION.SDK_INT; String methodName = null; if(currentVersion >= 16){ // 4.2 methodName = "setShowSoftInputOnFocus"; } else if(currentVersion >= 14){ // 4.0 methodName = "setSoftInputShownOnFocus"; } if(methodName == null){ ed.setInputType(InputType.TYPE_NULL); } else{ Class<EditText> cls = EditText.class; Method setShowSoftInputOnFocus; try { setShowSoftInputOnFocus = cls.getMethod(methodName, boolean.class); setShowSoftInputOnFocus.setAccessible(true); setShowSoftInputOnFocus.invoke(ed, false); } catch (NoSuchMethodException e) { ed.setInputType(InputType.TYPE_NULL); e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
3.对于有smartBar的手机,移动根布局可能不咋同,那么就不要移动跟布局,给要移动view添加一个id,然后移动该view就可以了。
if (null == (mContentView = ((Activity) context).findViewById(R.id.lay_linear))) { mContentView = ((Activity) context).getWindow().getDecorView().findViewById(Window.ID_ANDROID_CONTENT); } mPopupView = LayoutInflater.from(mcontext).inflate( R.layout.dialog_popupkeyboard, null);
4.Unable to add window -- token null is not valid; is your activity running?
等视图创建完成后,才能响应事件。
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { initView(); } }