为了账号安全,请及时绑定邮箱和手机立即绑定

仿微信 - 触摸除输入框以外的其它区域自动隐藏软键盘

标签:
Android

5be0592d0001ea1003420678.jpg



很多应用里面每次输入完一段文本过后要自己去隐藏软键盘,各种输入法、各种切换输入类型后、各种找不到隐藏软件盘的按钮。看到微信的好友聊天的时候点击输入框以外其它区域自动隐藏软键盘的功能非常实用就自己实现了一个。

实现思路:利用ViewGroup的dispatchTouchEvent拦截触摸事件,然后检查软件盘状态和点击位置是否为EditText, 如果不是就隐藏软键盘。

不多说直接上代码:

自定义控件 LinearLayoutAutoHintInputMethod 完美实现自动隐藏软键盘的功能,只需要把这个控件替换根布局中使用的布局就可以了。

如果不想使用LinearLayout布局,只需要将LinearLayout替换成其它ViewGroup就可以了。

/** 自动隐藏软件盘的布局 */
public class LinearLayoutAutoHintInputMethod extends LinearLayout {
    /** 自动隐藏软件盘的布局 */
    public LinearLayoutAutoHintInputMethod(Context context) {
        this (context, null);
    }
    /** 自动隐藏软件盘的布局 */
    public LinearLayoutAutoHintInputMethod(Context context, AttributeSet attrs) {
        this (context, attrs, 0);
    }
    /** 自动隐藏软件盘的布局 */
    public LinearLayoutAutoHintInputMethod(Context context, AttributeSet attrs, int defStyle) {
        super (context, attrs, defStyle);
        setFocusable (true);
        setFocusableInTouchMode (true);
    }
    @Override
    protected void onAttachedToWindow(){
        super.onAttachedToWindow ();
        initFocusChangeListener (this);
    }
    /** 初始化焦点变化监听 */
    private void initFocusChangeListener(ViewGroup v){
        for ( int i = 0 ; i < v.getChildCount () ; i++ ) {
            View view = v.getChildAt (i);
            view.setOnFocusChangeListener (mFocusChangeListener);
            if (view instanceof ViewGroup) {
                initFocusChangeListener ((ViewGroup) view);
            } else {
                ArrayList<View> TouchableViews = view.getTouchables ();
                for ( View child : TouchableViews ) {
                    child.setOnFocusChangeListener (mFocusChangeListener);
                }
            }
        }
    }
    /** 当前获得焦点的View */
    private View                  mCurrentFouceView    = null;
    private OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener () {
                                                           public void onFocusChange(View v,boolean hasFocus){
                                                               if (!hasFocus) mCurrentFouceView = null;
                                                               else mCurrentFouceView = v;
                                                           }
                                                       };
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev){
        if (ev.getAction () == MotionEvent.ACTION_DOWN) {
            // View v = ((Activity) getContext ()).getCurrentFocus ();
            View v = mCurrentFouceView;
            if (isShouldHideInput (v, ev)) { // 如果虚拟键盘为弹出状态执行一下操作
                // 还需要判断当前点击的地方不为另外一个EditText,否则会出现虚拟键盘跳跃的错误
                boolean isNextEditText = false;
                View clickView = getViewAtViewGroup ((int) ev.getX (), (int) ev.getY ());
                if (clickView != null && clickView instanceof EditText) isNextEditText = true;
                if (!isNextEditText) { // 一下点击的控件不是一个EditText
                    InputMethodManager imm = (InputMethodManager) getContext ().getSystemService (Context.INPUT_METHOD_SERVICE);
                    if (imm != null) {
                        imm.hideSoftInputFromWindow (v.getWindowToken (), 0);
                        v.clearFocus ();
                    }
                }
            }
        }
        return super.dispatchTouchEvent (ev);
    }
    /** 判断虚拟键盘是否被弹出 */
    public boolean isShouldHideInput(View v,MotionEvent event){
        if (v != null && (v instanceof EditText)) {
            int[] fatherLeftTop = { 0, 0 }; // 父控件在屏幕中的绝对坐标
            getLocationOnScreen (fatherLeftTop);
            int[] chileLeftTop = { 0, 0 };
            v.getLocationOnScreen (chileLeftTop);
            // 子控件在屏幕中的绝对坐标需要减去父控件的绝对坐标才能匹配真正的坐标
            int left = chileLeftTop[0] - fatherLeftTop[0];
            int top = chileLeftTop[1] - fatherLeftTop[1];
            int right = left + v.getWidth ();
            int bottom = top + v.getHeight ();
            if (new RectF (left,top,right,bottom).contains (event.getX (), event.getY ())) {
                // 点击的是输入框区域,保留点击EditText的事件
                return false;
            } else {
                return true;
            }
        }
        return false;
    }
    /**
     * 根据坐标获取相对应的子控件 在重写ViewGroup使用
     * 
     * @param x坐标
     * @param y坐标
     * @return 目标View
     */
    public View getViewAtViewGroup(int x,int y){
        return findViewByXY (this, x, y);
    }
    private View findViewByXY(View view,int x,int y){
        View targetView = null;
        if (view instanceof ViewGroup) {
            ViewGroup v = (ViewGroup) view;
            for ( int i = 0 ; i < v.getChildCount () ; i++ ) {
                targetView = findViewByXY (v.getChildAt (i), x, y);
                if (targetView != null) {
                    break;
                }
            }
        } else {
            targetView = getTouchTarget (view, x, y);
        }
        return targetView;
    }
    private View getTouchTarget(View view,int x,int y){
        // 判断view是否可以聚焦
        ArrayList<View> TouchableViews = view.getTouchables ();
        for ( View child : TouchableViews ) {
            if (isTouchPointInView (child, x, y)) { return child; }
        }
        return null;
    }
    private boolean isTouchPointInView(View view,int x,int y){
        int[] fatherLeftTop = { 0, 0 }; // 父控件在屏幕中的绝对坐标
        getLocationOnScreen (fatherLeftTop);
        int[] location = new int[2];
        view.getLocationOnScreen (location);
        int left = location[0] - fatherLeftTop[0];
        int top = location[1] - fatherLeftTop[1];
        int right = left + view.getMeasuredWidth ();
        int bottom = top + view.getMeasuredHeight ();
        Rect R = new Rect (left,top,right,bottom);
        if (view.isClickable () && R.contains (x, y)) { return true; }
        return false;
    }
}


Demo下载地址:http://download.csdn.net/detail/ftmtshuashua/9067007

原文链接:http://www.apkbus.com/blog-202342-59407.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消