EditText,清晰地关注外面的触摸

not*_*173 88 android focus android-edittext

我的布局包含ListView,SurfaceViewEditText.当我点击EditText它时,它会获得焦点并弹出屏幕键盘.当我点击EditText它之外的某个地方时,它仍然有焦点(它不应该).我想我可以OnTouchListener在布局中设置其他视图并手动清除EditText焦点.但似乎过于hackish ......

我在其他布局中也有相同的情况 - 列表视图中包含不同类型的项目,其中一些项目EditText位于内部.他们的行为就像我上面写的那样.

EditText当用户触摸外面的东西时,任务就是失去焦点.

我在这里看到过类似的问题,但没有找到任何解决方案......

zMa*_*Man 202

以Ken的答案为基础,这是最模块化的复制粘贴解决方案.

不需要XML.

将它放在您的Activity中,它将适用于所有EditTexts,包括该活动中片段内的那些.

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View v = getCurrentFocus();
        if ( v instanceof EditText) {
            Rect outRect = new Rect();
            v.getGlobalVisibleRect(outRect);
            if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                v.clearFocus();
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent( event );
}
Run Code Online (Sandbox Code Playgroud)

  • 看起来很好.我仍有一个问题,我的所有编辑文本都在滚动视图中,顶部编辑文本始终显示光标.即使我在外面点击,焦点也会丢失,键盘也会消失,但光标在顶部编辑文本中仍然可见. (11认同)
  • 我从未见过的最佳解决方案!我将这段代码保存到要点中,以传递给我的儿子和孙子。 (7认同)
  • 如果用户单击另一个 EditText,则键盘将立即关闭并重新打开。为了解决这个问题,我在代码中将“MotionEvent.ACTION_DOWN”更改为“MotionEvent.ACTION_UP”。顺便说一句,很好的答案! (4认同)
  • 我遇到的最佳解决方案!早些时候我使用 @Override public boolean onTouch(View v, MotionEvent event) { if(v.getId()!=search_box.getId()){ if(search_box.hasFocus()) { InputMethodManager imm = (InputMethodManager) getSystemService(上下文.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(search_box.getWindowToken(), 0); search_box.clearFocus(); 返回假;返回假;} (2认同)

Ken*_*Ken 65

我试过所有这些解决方案.edc598是最接近工作的,但触摸事件没有触发View布局中包含的其他内容.如果有人需要这种行为,这就是我最终做的事情:

我创建了一个FrameLayout名为touchInterceptor的(不可见)作为View布局中的最后一个,以便它覆盖所有内容(编辑:您还必须使用a RelativeLayout作为父布局并提供touchInterceptor fill_parent属性).然后我用它来拦截触摸并确定触摸是否在上面EditText:

FrameLayout touchInterceptor = (FrameLayout)findViewById(R.id.touchInterceptor);
touchInterceptor.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (mEditText.isFocused()) {
                Rect outRect = new Rect();
                mEditText.getGlobalVisibleRect(outRect);
                if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                    mEditText.clearFocus();
                    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
        }
        return false;
    }
});
Run Code Online (Sandbox Code Playgroud)

返回false以使触摸处理失效.

这很hacky,但它是唯一对我有用的东西.

  • 您可以通过覆盖活动中的dispatchTouchEvent(MotionEvent ev)而不添加其他布局来执行相同的操作. (18认同)

小智 32

对于EditText的父视图,让以下3个属性为" true ":
clickable,focusable,focusableInTouchMode.

如果视图想要获得焦点,则必须满足这3个条件.

android.view:

public boolean onTouchEvent(MotionEvent event) {
    ...
    if (((viewFlags & CLICKABLE) == CLICKABLE || 
        (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
        ...
        if (isFocusable() && isFocusableInTouchMode()
            && !isFocused()) {
                focusTaken = requestFocus();
        }
        ...
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.

  • 为了清除焦点,其他可聚焦视图必须是聚焦视图的父级.如果要关注的视图位于另一个层次结构上,它将无法工作. (2认同)

小智 18

只需将这些属性放在最顶层的父级中.

android:focusableInTouchMode="true"
android:clickable="true"
android:focusable="true" 
Run Code Online (Sandbox Code Playgroud)


Mik*_*tiz 15

肯的​​回答是有效的,但它很糟糕.正如pcans在答案的评论中暗示的那样,可以使用dispatchTouchEvent完成同样的事情.这个解决方案更清晰,因为它避免了使用透明的虚拟FrameLayout破解XML.这是看起来像:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    EditText mEditText = findViewById(R.id.mEditText);
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View v = getCurrentFocus();
        if (mEditText.isFocused()) {
            Rect outRect = new Rect();
            mEditText.getGlobalVisibleRect(outRect);
            if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                mEditText.clearFocus();
                //
                // Hide keyboard
                //
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent(event);
}
Run Code Online (Sandbox Code Playgroud)


Den*_* H. 7

这是我基于 zMan 代码的版本。如果下一个视图也是编辑文本,它不会隐藏键盘。如果用户只是滚动屏幕,它也不会隐藏键盘。

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        downX = (int) event.getRawX();
    }

    if (event.getAction() == MotionEvent.ACTION_UP) {
        View v = getCurrentFocus();
        if (v instanceof EditText) {
            int x = (int) event.getRawX();
            int y = (int) event.getRawY();
            //Was it a scroll - If skip all
            if (Math.abs(downX - x) > 5) {
                return super.dispatchTouchEvent(event);
            }
            final int reducePx = 25;
            Rect outRect = new Rect();
            v.getGlobalVisibleRect(outRect);
            //Bounding box is to big, reduce it just a little bit
            outRect.inset(reducePx, reducePx);
            if (!outRect.contains(x, y)) {
                v.clearFocus();
                boolean touchTargetIsEditText = false;
                //Check if another editText has been touched
                for (View vi : v.getRootView().getTouchables()) {
                    if (vi instanceof EditText) {
                        Rect clickedViewRect = new Rect();
                        vi.getGlobalVisibleRect(clickedViewRect);
                        //Bounding box is to big, reduce it just a little bit
                        clickedViewRect.inset(reducePx, reducePx);
                        if (clickedViewRect.contains(x, y)) {
                            touchTargetIsEditText = true;
                            break;
                        }
                    }
                }
                if (!touchTargetIsEditText) {
                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
        }
    }
    return super.dispatchTouchEvent(event);
}
Run Code Online (Sandbox Code Playgroud)


edc*_*598 5

你可能已经找到了这个问题的答案,但我一直在寻找如何解决这个问题,但仍然无法找到我想要的东西,所以我想我会在这里发布.

我所做的是以下(这是非常概括的,目的是让你知道如何继续,复制和粘贴所有代码将无法工作O:D):

首先让EditText和您在程序中想要的任何其他视图由单个视图包装.在我的例子中,我使用LinearLayout来包装所有内容.

<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/mainLinearLayout">
 <EditText
  android:id="@+id/editText"/>
 <ImageView
  android:id="@+id/imageView"/>
 <TextView
  android:id="@+id/textView"/>
 </LinearLayout>
Run Code Online (Sandbox Code Playgroud)

然后在您的代码中,您必须为主LinearLayout设置Touch Listener.

final EditText searchEditText = (EditText) findViewById(R.id.editText);
mainLinearLayout.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            if(searchEditText.isFocused()){
                if(event.getY() >= 72){
                    //Will only enter this if the EditText already has focus
                    //And if a touch event happens outside of the EditText
                    //Which in my case is at the top of my layout
                    //and 72 pixels long
                    searchEditText.clearFocus();
                    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
            Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
            return false;
        }
    });
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮助一些人.或者至少帮助他们开始解决问题.


Ada*_*hta 5

对我而言,事无巨细-

1. 添加android:clickable="true"android:focusableInTouchMode="true"parentLayoutEditText,即android.support.design.widget.TextInputLayout

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusableInTouchMode="true">
<EditText
    android:id="@+id/employeeID"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:ems="10"
    android:inputType="number"
    android:hint="Employee ID"
    tools:layout_editor_absoluteX="-62dp"
    tools:layout_editor_absoluteY="16dp"
    android:layout_marginTop="42dp"
    android:layout_alignParentTop="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_marginRight="36dp"
    android:layout_marginEnd="36dp" />
    </android.support.design.widget.TextInputLayout>
Run Code Online (Sandbox Code Playgroud)

2. 覆盖dispatchTouchEventActivity类和插入hideKeyboard()函数

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View view = getCurrentFocus();
            if (view != null && view instanceof EditText) {
                Rect r = new Rect();
                view.getGlobalVisibleRect(r);
                int rawX = (int)ev.getRawX();
                int rawY = (int)ev.getRawY();
                if (!r.contains(rawX, rawY)) {
                    view.clearFocus();
                }
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    public void hideKeyboard(View view) {
        InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }
Run Code Online (Sandbox Code Playgroud)

3. 为EditText 添加setOnFocusChangeListener

EmployeeId.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    hideKeyboard(v);
                }
            }
        });
Run Code Online (Sandbox Code Playgroud)