自定义键盘:
重写的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();
}
}