EditText,清除重点在外面的触摸

我的布局包含ListViewSurfaceViewEditText 。 当我点击EditText ,它会收到焦点,并popup屏幕上的键盘。 当我点击EditText之外的地方时,它仍然有焦点(不应该)。 我想我可以在布局中的其他视图上设置OnTouchListener ,并手动清除EditText的焦点。 但似乎太ha

在其他布局列表视图中,也有不同types的项目,其中一些内部有EditText 。 他们的行为就像我上面写的。

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

我在这里看到类似的问题,但还没有find任何解决scheme…

我试过所有这些解决scheme。 edc598's是最接近工作,但触摸事件没有触发其他View包含在布局。 如果任何人需要这种行为,这就是我最终做的事情:

我创build了一个名为touchInterceptor的(不可见的) FrameLayout作为布局中的最后一个View ,以便覆盖所有内容( 编辑:您还必须使用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; } }); 

返回false让触摸处理通过。

这是hacky,但它是唯一的工作对我来说。

Ken的答案是,这是最模块化的复制和粘贴解决scheme。

不需要XML。

把它放在你的活动中,它将应用于所有的EditTexts,包括那个Activity内的片段。

 @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 ); } 

对于EditText的父视图,让以下3个属性为“ true ”:
可点击可调焦focusableInTouchMode

如果一个观点要获得重点,就必须满足这三个条件。

请参阅android.view

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

希望它有帮助。

肯的​​答案是有效的,但是这很不好。 正如pcans暗示的答案的评论,同样的事情可以用dispatchTouchEvent完成。 这个解决scheme比较干净,因为它避免了用透明的虚拟FrameLayout来破解XML。 这是这样的:

 @Override public boolean dispatchTouchEvent(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(); // // Hide keyboard // InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } } } return super.dispatchTouchEvent(event); } 

你可能已经find了这个问题的答案,但我一直在寻找如何解决这个问题,仍然不能真正find我正在寻找什么,所以我想我会在这里发布。

我做的是以下(这是非常普遍的,目的是给你一个如何进行的想法,复制和粘贴所有的代码将不会工作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> 

然后在你的代码中,你必须设置一个Touch Listener到你的主LinearLayout。

 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; } }); 

我希望这有助于一些人。 或者至less帮助他们开始解决他们的问题。

当触及其他视图时失去焦点,应将这两个视图设置为view.focusableInTouchMode(true)。

但是,似乎不build议在触摸模式下使用焦点。 请看看这里: http : //android-developers.blogspot.com/2008/12/touch-mode.html

我有一个由EditText视图组成的ListView 。 该场景说,在编辑一行或多行文本后,我们应该点击一个名为“完成”的button。 我在onFocusChangedEditText视图中使用onFocusChanged ,但点击完成后,数据没有被保存。 问题是通过添加解决的

 listView.clearFocus(); 

在“完成”button的onClickListener ,数据已成功保存。

我真的认为使用getLocationOnScreengetGlobalVisibleRect更强大。 因为我遇到了一个问题。 有一个ListView包含一些Edittext,并在活动中设置一个ajustpan 。 我发现getGlobalVisibleRect返回一个看起来像包含getGlobalVisibleRect的值,但event.getRawY总是在屏幕上。 下面的代码运行良好。

 public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { View v = getCurrentFocus(); if ( v instanceof EditText) { if (!isPointInsideView(event.getRawX(), event.getRawY(), v)) { Log.i(TAG, "!isPointInsideView"); Log.i(TAG, "dispatchTouchEvent clearFocus"); v.clearFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } } } return super.dispatchTouchEvent( event ); } /** * Determines if given points are inside view * @param x - x coordinate of point * @param y - y coordinate of point * @param view - view object to compare * @return true if the points are within view bounds, false otherwise */ private boolean isPointInsideView(float x, float y, View view) { int location[] = new int[2]; view.getLocationOnScreen(location); int viewX = location[0]; int viewY = location[1]; Log.i(TAG, "location x: " + location[0] + ", y: " + location[1]); Log.i(TAG, "location xWidth: " + (viewX + view.getWidth()) + ", yHeight: " + (viewY + view.getHeight())); // point is inside view bounds return ((x > viewX && x < (viewX + view.getWidth())) && (y > viewY && y < (viewY + view.getHeight()))); } 

只要将这些属性放在最顶层的父项中。

 android:focusableInTouchMode="true" android:clickable="true" android:focusable="true" 

最好的方法是使用默认方法clearFocus()

你知道如何解决onTouchListener代码吗?

只需调用EditText.clearFocus() 。 它将清除last EditText焦点。

由于@pcansbuild议您可以在您的活动中重写dispatchTouchEvent(MotionEvent event)

在这里,我们得到触摸坐标,并将它们比较来查看边界。 如果在视图之外进行触摸,请执行一些操作。

 @Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { View yourView = (View) findViewById(R.id.view_id); if (yourView != null && yourView.getVisibility() == View.VISIBLE) { // touch coordinates int touchX = (int) event.getX(); int touchY = (int) event.getY(); // get your view coordinates final int[] viewLocation = new int[2]; yourView.getLocationOnScreen(viewLocation); // The left coordinate of the view int viewX1 = viewLocation[0]; // The right coordinate of the view int viewX2 = viewLocation[0] + yourView.getWidth(); // The top coordinate of the view int viewY1 = viewLocation[1]; // The bottom coordinate of the view int viewY2 = viewLocation[1] + yourView.getHeight(); if (!((touchX >= viewX1 && touchX <= viewX2) && (touchY >= viewY1 && touchY <= viewY2))) { Do what you want... // If you don't want allow touch outside (for example, only hide keyboard or dismiss popup) return false; } } } return super.dispatchTouchEvent(event); } 

另外,如果活动的布局在运行时不发生变化(例如,您不添加碎片或从布局中replace/删除视图),则不需要检查视图的存在和可见性。 但是,如果您想要closures(或者做类似的事情)自定义的上下文菜单(如在谷歌播放商店使用项目的溢出菜单时),有必要检查视图存在。 否则,你会得到一个NullPointerException

只需将该EditText的父项的两个属性定义为:

 android:clickable="true" android:focusableInTouchMode="true" 

因此,当用户将触摸EditText区域之外时,焦点将被移除,因为焦点将被转移到父视图。