公司出了新的需求,对话框上有三个输入框,有一个输入框调用系统键盘,有两个输入框调用自定义键盘。
思路:自定义Edittext,获取焦点时,弹出一个popuwindow。但是因为是在Dialog上,所以如果确定当前的页面是最麻烦的。下面是代码:
package cn.startinfo.dingdao.view;
public class KeyboardEditText extends EditText implements KeyboardView.OnKeyboardActionListener {
private Keyboard mKeyboard;
private KeyboardView mKeyboardView;
private Window mWindow;
private View mDecorView;
private View mContentView;
private PopupWindow mKeyboardWindow;
private boolean isNeedCustomKeyboard = true; // 是否启用自定义键盘
/**
* 输入框在被键盘弹出时,要被推上的距离
*/
private int mScrollDistance = 0;
public static int screenWidth = -1; // 未知宽高
public static int screenHeight = -1;
/**
* 不包含导航栏的高度
*/
public static int screenHeightNoNavBar = -1;
/**
* 实际内容高度, 计算公式:屏幕高度-导航栏高度-电量栏高度
*/
public static int screenContentHeight = -1;
public static float density = 1.0f;
public static int densityDpi = 160;
public KeyboardEditText(Context context) {
this(context, null);
}
public KeyboardEditText(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public KeyboardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttributes(context);
initKeyboard(context, attrs);
}
private void initKeyboard(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Keyboard);
if (array.hasValue(R.styleable.Keyboard_xml)) {
isNeedCustomKeyboard = true;
int xmlId = array.getResourceId(R.styleable.Keyboard_xml, 0);
mKeyboard = new Keyboard(context, xmlId);
mKeyboardView = (KeyboardView) LayoutInflater.from(context).inflate(R.layout.my_keyboard_view, null);
mKeyboardView.setKeyboard(mKeyboard);
mKeyboardView.setEnabled(true);
mKeyboardView.setPreviewEnabled(false);
mKeyboardView.setOnKeyboardActionListener(this);
mKeyboardWindow = new PopupWindow(mKeyboardView,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//showAtLocation这里去获取当前的页面
//如果是普通activity的页面
//mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.BOTTOM, 0, 0);甚至不需要这行代码
//原因
mKeyboardWindow.showAtLocation(((Activity)((ContextWrapper)getContext()).getBaseContext()).getWindow().getDecorView(),Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL,0,0);
mKeyboardWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
if (mScrollDistance > 0) {
int temp = mScrollDistance;
mScrollDistance = 0;
if (null != mContentView) {
mContentView.scrollBy(0, -temp);
}
}
}
});
} else {
isNeedCustomKeyboard = false;
}
array.recycle();
}
private void initAttributes(Context context) {
initScreenParams(context);
this.setLongClickable(false); // 设置EditText不可长按
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) {
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 boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
});
}
}
private void initScreenParams(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
display.getMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
density = metrics.density;
densityDpi = metrics.densityDpi;
screenHeightNoNavBar = screenHeight;
int version = Build.VERSION.SDK_INT;
// 新版本的android 系统有导航栏,造成无法正确获取高度
if (version == 13) {
try {
Method method = display.getClass().getMethod("getRealHeight");
screenHeightNoNavBar = (Integer) method.invoke(display);
} catch (Exception e) {
// do nothing
}
} else if (version > 13) {
try {
Method method = display.getClass().getMethod("getRawHeight");
screenHeightNoNavBar = (Integer) method.invoke(display);
} catch (Exception e) {
// do nothing
}
}
screenContentHeight = screenHeightNoNavBar - getStatusBarHeight(context);
}
/**
* 获取状态栏高度
*/
private int getStatusBarHeight(Context context) {
Class<?> clazz = null;
Object object = null;
Field field = null;
int x = 0;
int statusBarHeight = 0;
try {
clazz = Class.forName("com.android.internal.R$dimen");
object = clazz.newInstance();
field = clazz.getField("status_bar_height");
x = Integer.parseInt(field.get(object).toString());
statusBarHeight = context.getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return statusBarHeight;
}
@Override
public void onPress(int primaryCode) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
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(0x0<=primaryCode&& primaryCode<=0x7f){
editable.insert(start, Character.toString((char) primaryCode));
}
//ASCII为0-127,若要自定义获取keylabel的值,则需要超过127
//附上ASCII表链接http://www.asciima.com/
else if(primaryCode >0x7f){
Keyboard.Key key = getKeyByKeyCode(primaryCode);
editable.insert(start, key.label);
}else{
}
}
private Keyboard.Key getKeyByKeyCode(int primaryCode) {
if(null != mKeyboard){
List<Key> keyList = mKeyboard.getKeys();
for (int i =0,size= keyList.size(); i < size; i++) {
Key key = keyList.get(i);
int codes[] = key.codes;
if(codes[0] == primaryCode){
return key;
}
}
}
return null;
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
requestFocus();
requestFocusFromTouch();
if (isNeedCustomKeyboard) {
hideSysInput();
showKeyboard();
}
return true;
}
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);
}
public void onAttachedToWindow(){
super.onAttachedToWindow();
//如果是普通的activity页面
//则代码为this.mWindow = ((Activity)getContext()).getWindow();
//具体原因参见http://www.imooc.com/article/7831
this.mWindow = ((Activity)((ContextWrapper)getContext()).getBaseContext()).getWindow();
this.mDecorView =this.mWindow .getDecorView();
this.mContentView =this.mWindow.findViewById(Window.ID_ANDROID_CONTENT);
hideSysInput();
}
public void onDetachedFromWindow(){
super.onDetachedFromWindow();
hideKeyboard();
mKeyboardWindow = null;
mKeyboardView = null;
mKeyboard = null;
mDecorView = null;
mContentView = null;
mWindow = null;
}
private void showKeyboard() {
if (null != mKeyboardWindow) {
if (!mKeyboardWindow.isShowing()) {
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();
mDecorView.getWindowVisibleDisplayFrame(outRect);
int screen = screenContentHeight;
mScrollDistance = (int) ((pos[1] + getMeasuredHeight() - outRect.top) - (screen - height));
if (mScrollDistance > 0) {
mContentView.scrollBy(0,mScrollDistance);
}
}
}
}
}
public void hideKeyboard() {
if (null != mKeyboardWindow) {
if (mKeyboardWindow.isShowing()) {
mKeyboardWindow.dismiss();
}
}
}
/**
* 密度转换为像素值
*/
private float dpToPx(Context context, int dp) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
private void hideSysInput() {
if (this.getWindowToken() != null) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
class KeyModel {
private Integer code;
private String label;
public KeyModel(Integer code, String label) {
this.code = code;
this.label = label;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
@Override
public String toString() {
return "code:"+code+","+"label:"+label;
}
}
}
xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<!-- 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的android:codes值必须配置为该字符的ASCII码 -->
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="25%p" android:horizontalGap="1px"
android:verticalGap="1px" android:keyHeight="@dimen/key_height">
<Row>
<Key android:codes="49" android:keyLabel="1"/>
<Key android:codes="50" android:keyLabel="2" />
<Key android:codes="51" android:keyLabel="3"/>
<Key android:codes="43" android:keyLabel="+"/>
</Row>
<Row>
<Key android:codes="52" android:keyLabel="4" />
<Key android:codes="53" android:keyLabel="5" />
<Key android:codes="54" android:keyLabel="6" />
<Key android:codes="45" android:keyLabel="-"/>
</Row>
<Row>
<Key android:codes="55" android:keyLabel="7" />
<Key android:codes="56" android:keyLabel="8" />
<Key android:codes="57" android:keyLabel="9" />
<Key android:codes="-5" android:keyLabel="删除" android:keyIcon="@color/red" />
</Row>
<Row>
<Key android:codes="128"
android:keyLabel="宽"
/>
<!--<Key android:codes="484848" android:keyLabel="000"-->
<!--android:keyWidth="34%p"/>-->
<Key android:codes="48" android:keyLabel="0"/>
<Key android:codes="129" android:keyLabel="高"
/>
<Key android:codes="-3" android:keyLabel="隐藏"/>
</Row>
</Keyboard>
public class MyKeyboardView extends KeyboardView {
private Drawable mKeyBgDrawable;
private Drawable mOpKeyBgDrawable;
private Resources mRes;
public MyKeyboardView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initResources(context);
}
private void initResources(Context context) {
mRes = context.getResources();
mKeyBgDrawable = mRes.getDrawable(R.drawable.btn_keyboard_key);
mOpKeyBgDrawable = mRes.getDrawable(R.drawable.btn_keyboard_opkey);
}
@Override
public void onDraw(Canvas canvas) {
List<Keyboard.Key> keys = getKeyboard().getKeys();
for (Keyboard.Key key : keys) {
canvas.save();
int offsetY = 0;
if (key.y == 0) {
offsetY = 1;
}
int initDrawY = key.y + offsetY;
Rect rect = new Rect(key.x, initDrawY, key.x + key.width, key.y + key.height);
canvas.clipRect(rect);
int primaryCode = -1;
if (null != key.codes && key.codes.length != 0) {
primaryCode = key.codes[0];
}
Drawable drawable = null;
if (primaryCode == -3 || key.codes[0] == -5) {
drawable = mOpKeyBgDrawable;
} else if (primaryCode != -1) {
drawable = mKeyBgDrawable;
}
if (null != drawable) {
int[] state = key.getCurrentDrawableState();
drawable.setState(state);
drawable.setBounds(rect);
drawable.draw(canvas);
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(50);
paint.setStrokeWidth(2);
paint.setColor(mRes.getColor(R.color.black));
if (key.label != null) {
canvas.drawText(
key.label.toString(),
key.x + (key.width / 2),
initDrawY + (key.height + paint.getTextSize() - paint.descent()) / 2,
paint
);
} else if (key.icon != null) {
int intriWidth = key.icon.getIntrinsicWidth();
int intriHeight = key.icon.getIntrinsicHeight();
final int drawableX = key.x + (key.width - intriWidth) / 2;
final int drawableY = initDrawY + (key.height - intriHeight) / 2;
key.icon.setBounds(drawableX, drawableY,
drawableX + intriWidth, drawableY + intriHeight);
key.icon.draw(canvas);
}
canvas.restore();
}
}
}
最后自定义键盘和系统键盘的切换
//调用系统键盘
mEdiMingcheng.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
mEditDongkou.hideKeyboard();
dialog.getWindow()
.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}
});
//调用自定义键盘
mEditDongkou.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
dialog.getWindow()
.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}
});