美文网首页Android 技术开发自定义views Android转载
Android软键盘与EditText近乎完美的交互

Android软键盘与EditText近乎完美的交互

作者: androidman | 来源:发表于2017-09-04 18:25 被阅读498次
    fastandrutlis开发框架

    android使用EditText的时候总是遇到一些很不爽的问题:

    无图无真相。。
    1.点击屏幕其他的任何位置,软键盘不会隐藏
    2.软键盘会把输入框遮盖掉


    bb.gif

    3.软键盘会把界面顶起


    cc.gif
    由于对键盘和EditText的种种不爽,就弄了一个以下东西
    aa.gif

    一.首先要知道怎么用代码控制软键盘的显示隐藏

    以下是软键盘显示隐藏类 KeyBoardUtils.java

    
    import android.app.Activity;
    import android.content.Context;
    import android.view.View;
    import android.view.inputmethod.InputMethodManager;
    import android.widget.EditText;
    
    import static android.content.Context.INPUT_METHOD_SERVICE;
    
    /**
     * @author laijian
     * @version 2017/8/29
     * @Copyright (C)下午2:55 , Suntektech
     */
    public class KeyBoardUtils {
        /**
         * 打开软键盘
         *
         * @param mEditText
         * @param mContext
         */
        public static void openKeybord(EditText mEditText, Context mContext) {
            InputMethodManager imm = (InputMethodManager) mContext
                    .getSystemService(INPUT_METHOD_SERVICE);
            imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);
            imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,
                    InputMethodManager.HIDE_IMPLICIT_ONLY);
        }
    
        /**
         * 关闭软键盘
         *
         * @param mEditText
         * @param mContext
         */
        public static void closeKeybord(EditText mEditText, Context mContext) {
            InputMethodManager imm = (InputMethodManager) mContext.getSystemService(INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
        }
    
    
        /**
         * des:隐藏软键盘,这种方式参数为activity
         *
         * @param activity
         */
        public static void hideInputForce(Activity activity) {
            if (activity == null || activity.getCurrentFocus() == null)
                return;
            ((InputMethodManager) activity.getSystemService(INPUT_METHOD_SERVICE))
                    .hideSoftInputFromWindow(activity.getCurrentFocus()
                            .getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    
        /**
         * 打开键盘
         **/
        public static void showInput(Context context, View view) {
            InputMethodManager imm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE);
            if (imm != null) {
                view.requestFocus();
                imm.showSoftInput(view, 0);
            }
        }
    
    
    
    
    }
    
    

    这个类没什么好说的

    二.要知道软键盘弹出时的高度

    获取软键盘弹出的高度是为了创建一个自适应的dialog,键盘弹出时就会在键盘上方显示一个带EditText的dialog
    以下是获取软键盘高度的类 KeyBoardHeightUtils.java

    
    import android.app.Activity;
    import android.graphics.Rect;
    import android.os.Build;
    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.widget.FrameLayout;
    
    /**
     * @author laijian
     * @version 2017/8/31
     * @Copyright (C)上午11:11 , Suntektech
     */
    public class KeyBoardHeightUtils {
        private View mChildOfContent;//activity 的布局View
        private int usableHeightPrevious;//activity的View的可视高度
        private KeyBoardHigthListener keyBoardHigthListener;
    
        public static KeyBoardHeightUtils setKeyBoardHeigthListener(Activity activity, KeyBoardHigthListener keyBoardHigthListener) {
            return new KeyBoardHeightUtils(activity, keyBoardHigthListener);
        }
    
        public void removeKeyboardHeightListener() {
            if (mChildOfContent == null) {
                return;
            }
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                mChildOfContent.getViewTreeObserver().removeGlobalOnLayoutListener(globalLayoutListener);
            } else {
                mChildOfContent.getViewTreeObserver().removeOnGlobalLayoutListener(globalLayoutListener);
            }
        }
    
        private KeyBoardHeightUtils(final Activity activity, KeyBoardHigthListener keyBoardHigthListener) {
            this.keyBoardHigthListener = keyBoardHigthListener;
    //获取安卓activity的最顶级控件
            FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);//
            mChildOfContent = content.getChildAt(0);
     //监听视图高度变化      mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener);
    //点击父控件隐藏软键盘
            mChildOfContent.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    KeyBoardUtils.hideInputForce(activity);
                }
            });
        }
    
        private ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    
            @Override
            public void onGlobalLayout() {
                possiblyResizeChildOfContent();
            }
        };
    
    
        private void possiblyResizeChildOfContent() {
            int usableHeightNow = computeUsableHeight();
            if (usableHeightNow != usableHeightPrevious) {
                int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
                int heightDifference = usableHeightSansKeyboard - usableHeightNow;
    //为了去除无谓的干扰,限制下高度
                if (heightDifference > (usableHeightSansKeyboard / 4)) {
                    keyBoardHigthListener.keyBoardHigthListener(usableHeightSansKeyboard - heightDifference, true, mChildOfContent);
                } else {
                    keyBoardHigthListener.keyBoardHigthListener(usableHeightSansKeyboard, false, mChildOfContent);
                }
                usableHeightPrevious = usableHeightNow;
            }
        }
    //获取控件在屏幕的可视高度,就是界面除去了标题栏、除去了被软键盘挡住的部分,所剩下的矩形区域
        private int computeUsableHeight() {
            Rect r = new Rect();
            mChildOfContent.getWindowVisibleDisplayFrame(r);
            return (r.bottom - r.top);
        }
    
    
        interface KeyBoardHigthListener {//这个回调类写的不好,请自行修改
            void keyBoardHigthListener(int heigth, boolean showKeyBoard, View contentView);
        }
    
    
    }
    
    

    这代码也不多 也不难理解

    三.要知道EditText控件是否被遮盖

    判断EditText控件是否被遮盖是为了弹出一个带EditText 的 dialog 这样就不会说EditText被覆盖后 不知道输入了些什么内容

    以下是检测EditText控件是否被覆盖

     private boolean checkViewVisiable() {
            Rect localRect = new Rect();
            boolean visiable = edtextVew.getLocalVisibleRect(localRect);
            System.out.println("visiable=" + visiable);
            return visiable;
        }
    

    以下是判断获取的焦点是不是EditText

      View childView = contentView.findFocus();
                    if (childView != null) {
                        if (childView instanceof EditText) {
                            edtextVew = (EditText) childView;
    

    以下类就是关键类,判断EditText是否被覆盖,弹dialog等
    KeyBoardUI.java

    
    import android.app.Activity;
    import android.app.Dialog;
    import android.content.Context;
    import android.graphics.Rect;
    import android.text.Editable;
    import android.text.TextUtils;
    import android.text.TextWatcher;
    import android.util.DisplayMetrics;
    import android.view.KeyEvent;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.Window;
    import android.view.WindowManager;
    import android.widget.EditText;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    import com.univercityapp.convergelibrary.widget.NullMenuEditText;
    
    /**
     * @author laijian
     * @version 2017/8/31
     * @Copyright (C)上午11:57 , Suntektech
     */
    public class KeyBoardUI implements KeyBoardHeightUtils.KeyBoardHigthListener {
    
        private EditText edtextVew;//activity的输入框
        private Activity activity;
        private Dialog mDialog;
        private NullMenuEditText popuEdtext;//popu的输入框
        private int screenWeight = 0;//屏幕宽度
        private KeyBoardHeightUtils keyBoardHeightUtils;
    
        public static KeyBoardUI buildKeyBoardUI(Activity activity) {
            return new KeyBoardUI(activity);
        }
    
    
        private KeyBoardUI(Activity activity) {
            this.activity = activity;
            getScreen();
            initDialog();
            keyBoardHeightUtils = KeyBoardHeightUtils.setKeyBoardHeigthListener(activity, this);
        }
    
        private void getScreen() {
            DisplayMetrics dm = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
            screenWeight = dm.widthPixels;
        }
    
        private void initDialog() {
            LayoutInflater inflater = (LayoutInflater) activity.getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View popuView = inflater.inflate(ResourcesUtils.getLayoutResources(activity, "popuwindow"), null);
            RelativeLayout populay = (RelativeLayout) popuView.findViewById(ResourcesUtils.getIdResources(activity, "popu_lay"));
            popuEdtext = (NullMenuEditText) popuView.findViewById(ResourcesUtils.getIdResources(activity, "ed_text"));
            mDialog = new Dialog(activity, ResourcesUtils.getStyleResources(activity, "dialog"));
            mDialog.setContentView(popuView);
            populay.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    KeyBoardUtils.closeKeybord(popuEdtext, activity);
                    mDialog.dismiss();
                }
            });
    
        }
    
        @Override
        public void keyBoardHigthListener(int heigth, boolean showKeyBoard, View contentView) {
            if (showKeyBoard) {
                if (contentView != null) {
                    View childView = contentView.findFocus();
                    if (childView != null) {
                        if (childView instanceof EditText) {
                            edtextVew = (EditText) childView;
                            if (!checkViewVisiable()) {
                                mDialog.show();
    //重新调整dialog的高度
                                Window dialogWindow = mDialog.getWindow();
                                WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 获取对话框当前的参数值
                                p.height = heigth; 
                                p.width = screenWeight; 
                                dialogWindow.setAttributes(p);
                                dialogWindow.setWindowAnimations(ResourcesUtils.getStyleResources(activity, "PopupAnimation"));
                                onEdChange();
                                KeyBoardUtils.openKeybord(edtextVew, activity);
                            } else {
                                if (mDialog != null) {
                                    mDialog.dismiss();
                                }
                            }
                        }
                    }
                }
            } else {
                if (mDialog != null) {
                    mDialog.dismiss();
                }
            }
        }
    
        private boolean checkViewVisiable() {
            Rect localRect = new Rect();
            boolean visiable = edtextVew.getLocalVisibleRect(localRect);
            System.out.println("visiable=" + visiable);
            return visiable;
        }
    
        private void onEdChange() {
            String hintStr = "";
            String text = "";
            if (!TextUtils.isEmpty(edtextVew.getText())) {
                text = edtextVew.getText().toString();
            }
            if (!TextUtils.isEmpty(edtextVew.getHint())) {
                hintStr = edtextVew.getHint().toString();
            }
            popuEdtext.findFocus();
            popuEdtext.setInputType(edtextVew.getInputType());
            popuEdtext.setHint(hintStr);
            popuEdtext.setText(text);
            popuEdtext.setSelection(text.length());
            popuEdtext.setMaxEms(edtextVew.getMaxEms());
            popuEdtext.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    edtextVew.setText(s);
                    edtextVew.setSelection(s.length());
                }
    
                @Override
                public void afterTextChanged(Editable s) {
    
                }
            });
    
            popuEdtext.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                @Override
                public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                    if (actionId == 0) {
                        KeyBoardUtils.closeKeybord(popuEdtext, activity);
                        mDialog.dismiss();
                        return true;
                    }
                    return false;
                }
            });
        }
    
        public void removeKeyboardHeightListener() {
            keyBoardHeightUtils.removeKeyboardHeightListener();
        }
    }
    
    

    四.禁止EditText长按出复制粘贴

    NullMenuEditText.java

    
    /**
     * @author laijian
     * @version 2017/8/30
     * @Copyright (C)下午5:26 , Suntektech
     */
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.ActionMode;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.EditText;
    
    /**
     * Created by jianjun.lin on 16/4/12.
     */
    public class NullMenuEditText extends EditText {
    
        boolean canPaste() {
            return false;
        }
    
        boolean canCut() {
            return false;
        }
    
        boolean canCopy() {
            return false;
        }
    
        boolean canSelectAllText() {
            return false;
        }
    
        boolean canSelectText() {
            return false;
        }
    
        boolean textCanBeSelected() {
            return false;
        }
    
        public NullMenuEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
            setLongClickable(false);
            setTextIsSelectable(false);
            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) {
    
                }
            });
    
        }
    
        @Override
        public boolean onTextContextMenuItem(int id) {
            return true;
        }
    }
    
    

    五.相关xml资源

    还有一些动画效果资源
    popup_enter.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:duration="100"
            android:fromYDelta="1"
            android:toYDelta="0" />
        <alpha
            android:duration="100"
            android:fromAlpha="0.0"
            android:toAlpha="1.0" />
    </set>
    
    

    popup_exit.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:duration="100"
            android:fromYDelta="0"
            android:toYDelta="1" />
        <alpha
            android:duration="100"
            android:fromAlpha="1.0"
            android:toAlpha="0.0" />
    </set>
    
    

    styles资源

     <style name="PopupAnimation" mce_bogus="1" parent="android:Animation">
            <item name="android:windowEnterAnimation">@anim/popup_enter</item>
            <item name="android:windowExitAnimation">@anim/popup_exit</item>
        </style>
    
        <style name="dialog" parent="android:style/Theme.Dialog">
            <item name="android:background">#00000000</item>
            <item name="android:windowBackground">@android:color/transparent</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:windowIsFloating">true</item>
            <item name="android:backgroundDimEnabled">false</item>
        </style>
    

    layout文件
    popuwindow.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/popu_lay"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#00000000">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="#ffffff"
            android:orientation="vertical"
            android:paddingTop="2dp">
    
            <com.univercityapp.convergelibrary.widget.NullMenuEditText
                android:id="@+id/ed_text"
                android:layout_width="match_parent"
                android:layout_height="36dp"
                android:paddingLeft="6dp"
                android:background="#ffffff"
                android:gravity="center_vertical"
                android:inputType="text"
                android:maxLines="1"
                android:scrollHorizontally="true"
                android:textSize="16sp" />
        </LinearLayout>
    </RelativeLayout>
    

    六.获取R的资源utils

    ResourcesUtils.java

    
    import android.content.Context;
    import android.content.res.Resources;
    
    import java.lang.reflect.Field;
    
    /**
     * Created by laijian code on 2016-10-19.
     */
    public class ResourcesUtils {
        public static int getIdResources(Context context, String idName) {
            Resources res = context.getResources();
            return res.getIdentifier(idName, "id", context.getPackageName());
        }
        public static int getDrawableResources(Context context, String drawableName) {
            Resources res = context.getResources();
            return res.getIdentifier(drawableName, "drawable", context.getPackageName());
        }
    
        public static int getColorResources(Context context, String colorName) {
            Resources res = context.getResources();
            return res.getIdentifier(colorName, "color", context.getPackageName());
        }
    
        public static int getStringResources(Context context, String stringName) {
            Resources res = context.getResources();
            return res.getIdentifier(stringName, "string", context.getPackageName());
        }
    
        public static int getLayoutResources(Context context, String LayoutName) {
            Resources res = context.getResources();
            return res.getIdentifier(LayoutName, "layout", context.getPackageName());
        }
    
        public static int getAttrResources(Context context, String attrName) {
            Resources res = context.getResources();
            return res.getIdentifier(attrName, "attr", context.getPackageName());
        }
    
        public static int getStyleResources(Context context, String attrName) {
            Resources res = context.getResources();
            return res.getIdentifier(attrName, "style", context.getPackageName());
        }
    
        /**
         * context.getResources().getIdentifier 无法获取到 styleable 的数据
         *
         * @param name
         * @return
         * @paramcontext
         */
    
        public static int getStyleable(Context context, String name) {
    
            return ((Integer) getResourceId(context, name, "styleable")).intValue();
    
        }
    
        /**
         * 获取 styleable 的 ID 号数组
         *
         * @param name
         * @return
         * @paramcontext
         */
        public static int[] getStyleableArray(Context context, String name) {
    
            return (int[]) getResourceId(context, name, "styleable");
    
        }
        /**
         * 对于 context.getResources().getIdentifier 无法获取的数据 , 或者数组
         * <p/>
         * 资源反射值
         *
         * @param name
         * @param type
         * @return
         * @paramcontext
         */
    
        private static Object getResourceId(Context context, String name, String type) {
    
            String className = context.getPackageName() + ".R";
    
            try {
    
                Class<?> cls = Class.forName(className);
    
                for (Class<?> childClass : cls.getClasses()) {
    
                    String simple = childClass.getSimpleName();
    
                    if (simple.equals(type)) {
    
                        for (Field field : childClass.getFields()) {
    
                            String fieldName = field.getName();
                            if (fieldName.equals(name)) {
                                System.out.println(fieldName);
                                return field.get(null);
    
                            }
    
                        }
    
                    }
    
                }
    
            } catch (Exception e) {
    
                e.printStackTrace();
    
            }
    
            return null;
    
        }
    }
    
    

    七.如何使用

    使用非常简单,在需要的activity的oncreat方法添加

            KeyBoardUI.buildKeyBoardUI(this);
    
    

    在AndroidManifest.xml用到上面方法的activity添加

    android:windowSoftInputMode="adjustResize"
    

    谢谢观看完以上内容
    欢迎访问个人博客
    github地址,喜欢就star下

    相关文章

      网友评论

      本文标题:Android软键盘与EditText近乎完美的交互

      本文链接:https://www.haomeiwen.com/subject/gyvejxtx.html