EditView外部点击隐藏软键盘需求

业务场景

在工作过程中,遇到一个需求。某个页面,需要在EditView输入数值,在软键盘下滑和点击EditView外部区域后,EditView失去焦点,并且开始计算最终金额。因为该页面没有其他控件可以抢占EditView焦点,所以需要做一些额外处理来完成这个需求。下面是步骤

第一步,重写EditView父控件的事件分发方法,判断是否有外部点击

使用下面这个类,判断是否是EditView的外部点击。还可以调用addList(View)方法,把该父布局下的子控件同时加入判断,判断这些子控件和EditView的区域外点击。
调用步骤,

  1. 在xml中,把这个DispatchTouchFrameLayout当作EditView的父控件,这里也可以修改成RelativeLayout或者LinearLayout都可以。
  2. setEditView(EditView) 加入判断的editView
  3. addList(View) 加入需要判断的其他View,可选
  4. setRunnable(Runnable),添加触发后的响应事件

/**
 * created time: 2019/6/18
 * 可判断是否在EditView以外区域发生了点击
 */
public class DispatchTouchFrameLayout extends FrameLayout {

    public DispatchTouchFrameLayout(@NonNull Context context) {
        super(context);
    }

    public DispatchTouchFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public DispatchTouchFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    EditText editText;
    //其他不响应区域view
    ArrayList<View> notCheckViewList = new ArrayList<>();

    public void addList(View view) {
        notCheckViewList.add(view);
    }

    private EditText getEditText() {
        return editText;
    }

    public void setEditText(EditText editText) {
        this.editText = editText;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        this.editText = null;
        notCheckViewList.clear();
        notCheckViewList = null;
    }

    //点击以外区域后的响应事件
    Runnable runnable;

    public void setRunnable(Runnable runnable) {
        this.runnable = runnable;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            EditText v = getEditText();
            if (isShouldHideInput(v, ev)) {
                if (runnable != null)
                    runnable.run();
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 是否应该触发eidtView区域外的点击事件
     *
     * @param v
     * @param event
     * @return
     */
    private boolean isShouldHideInput(EditText v, MotionEvent event) {
        if (v != null && v.isFocused()) {
            boolean isOnEditView = isOnViewArea(v, event);
            if (isOnEditView) return false;
            //点击其他list内view区域,也不响应
            for (View view : notCheckViewList) {
                boolean onViewArea = isOnViewArea(view, event);
                isOnEditView = isOnEditView || onViewArea;
            }
            return !isOnEditView;
        }
        return false;
    }

    /**
     * 判断某个点击时间是否在这个view区域内
     *
     * @param view
     * @param event
     * @return true表示在范围内
     */
    private boolean isOnViewArea(View view, MotionEvent event) {
        if (view == null) return false;
        int[] leftTop = {0, 0};
        //获取输入框当前的location位置
        view.getLocationInWindow(leftTop);
        //取window坐标
        int[] containerTop = {0, 0};
        getLocationInWindow(containerTop);
        int left = leftTop[0];
        int top = leftTop[1];
        int bottom = top + view.getHeight();
        int right = left + view.getWidth();
        float x = containerTop[0] + event.getX();
        float y = containerTop[1] + event.getY();
        return x > left && x < right
                && y > top && y < bottom;
    }

}

第二步,监听软键盘下滑事件

监听软件盘下滑事件,setOnSoftKeyBoardChangeListener(), keyBoardHide()触发时响应runnable

/**
 * description: 软键盘弹起和下滑监听类
 */
public class KeyBoardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
    View rootView;
    int rootViewVisibleHeight; //纪录根视图的显示高度,每次改变重新赋值
    final int HEIGHT_BOUND = 200;       //200px为判断界限值

    public KeyBoardChangeListener(Activity activity) {
        if (activity == null)
            return;
        rootView = findContentView(activity);
        addContentTreeObserver();
    }

    private View findContentView(Activity activity) {
        return activity.getWindow().getDecorView();
    }

    private void addContentTreeObserver() {
        if (rootView != null)
            rootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        Rect r = new Rect();
        rootView.getWindowVisibleDisplayFrame(r);
        int visibleHeight = r.height();
        if (rootViewVisibleHeight == 0) {   //初始化高度
            rootViewVisibleHeight = visibleHeight;
            return;
        }
        //可见高度不变,未发生软键盘变化
        if (rootViewVisibleHeight == visibleHeight)
            return;
        int diffHeight = Math.abs(rootViewVisibleHeight - visibleHeight);
        if (diffHeight > HEIGHT_BOUND) {                         //如果变化高度大于界限
            if (rootViewVisibleHeight > visibleHeight) {        //可见高度变小,表示软键盘弹出
                if (onSoftKeyBoardChangeListener != null)
                    onSoftKeyBoardChangeListener.keyBoardShow(diffHeight);
            } else {
                if (onSoftKeyBoardChangeListener != null)
                    onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
            }
            rootViewVisibleHeight = visibleHeight;
        }
    }

    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;

    public void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }

    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide(int height);
    }

    public void release() {
        if (rootView != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
                rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
        rootView = null;
    }
}

第三步,隐藏软键盘和取消EditView焦点

运行的runnable事件中,加上隐藏软键盘,取消EditView焦点,开始计算等逻辑即可

//隐藏软键盘
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(((Activity) context).getWindow().getDecorView().getWindowToken(), 0);

//EditView取消焦点和光标
editView.clearFocus();
### 回答1: 你好,对于你的问题,可以通过以下步骤来实现在点击editview外的区域时,收回键盘: 1. 在XML布局文件中,将外层布局设置为可点击,并设置其焦点。 例如: ``` <RelativeLayout android:id="@+id/mainLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true"> <!-- EditView --> </RelativeLayout> ``` 2. 在Activity中获取外层布局,并设置监听器,当点击外层布局时,收回键盘。 例如: ``` RelativeLayout mainLayout = findViewById(R.id.mainLayout); mainLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } }); ``` 这样,当用户点击外层布局时,键盘就会被收回。 ### 回答2: 可以通过以下步骤实现在点击EditText外的区域时收回键盘的功能。 1. 首先,在方法类中创建一个公共方法,在其中监听整个布局的触摸事件。代码如下: ```java public class KeyboardUtils { public static void hideKeyboardOnOutsideClick(Activity activity, View rootView) { if (!(rootView instanceof EditText)) { rootView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { hideKeyboard(activity); return false; } }); } if (rootView instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) rootView; for (int i = 0; i < viewGroup.getChildCount(); i++) { View innerView = viewGroup.getChildAt(i); hideKeyboardOnOutsideClick(activity, innerView); } } } private static void hideKeyboard(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); View focusedView = activity.getCurrentFocus(); if (focusedView != null) { inputMethodManager.hideSoftInputFromWindow(focusedView.getWindowToken(), 0); focusedView.clearFocus(); } } } ``` 2. 然后,在需要使用该功能的Activity中,例如MainActivity,在合适的地方调用该方法,并传入根布局的视图对象。例如,可以在onCreate方法的末尾调用,代码如下: ```java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); View rootView = findViewById(android.R.id.content); KeyboardUtils.hideKeyboardOnOutsideClick(MainActivity.this, rootView); } // 其他代码... } ``` 这样,在点击EditText以外的区域时,键盘将会被收回。方法类会遍历整个布局,捕获所有非EditText视图的触摸事件,并在触摸事件发生时调用hideKeyboard方法隐藏键盘。 ### 回答3: 要在点击editview外的区域时收回键盘,可以使用以下方法: 首先,创建一个方法类,命名为KeyboardUtil。 在KeyboardUtil类中,定义一个静态方法hideKeyboard,传入一个Context对象和一个View对象作为参数。 在hideKeyboard方法中,使用InputMethodManager类来控制键盘的显示与隐藏。 首先,通过Context.getSystemService(Context.INPUT_METHOD_SERVICE)获取InputMethodManager对象。 然后,使用InputMethodManager的hideSoftInputFromWindow方法,将View对象和InputMethodManager.HIDE_IMPLICIT_ONLY作为参数传入,实现隐藏键盘的功能。 在需要使用隐藏键盘功能的地方,调用KeyboardUtil.hideKeyboard方法即可。比如,在Activity的onCreate方法中,可以通过findViewById方法获取editview对象,然后使用KeyboardUtil.hideKeyboard(this, editview)来实现在点击editview外的区域时收回键盘。 在点击editview外的区域时,可以通过设置一个监听器来实现隐藏键盘的功能。比如,可以在Activity的布局文件中的最外层布局中设置一个OnClickListener监听器。当点击该布局时,即可触发点击editview外的区域的事件,在事件中调用KeyboardUtil.hideKeyboard方法隐藏键盘。 以上就是使用方法类实现在点击editview外的区域时收回键盘的步骤。这样可以提供用户更好的使用体验,避免键盘挡住视图的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值