点击EditText外部后如何在android上隐藏软键盘?
好的,大家都知道,要隐藏你需要实现的键盘:
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
但是这里最重要的是如何在用户触摸或select任何不是EditText
或softKeyboard的地方时隐藏键盘?
我试图在我的父Activity
上使用onTouchEvent()
,但只有当用户触及任何其他视图之外,并且没有滚动视图时才起作用。
我试图实现一个触摸,点击,重点监听没有任何成功。
我甚至试图实现我自己的滚动视图来拦截触摸事件,但我只能得到事件的坐标而不是点击的视图。
有没有一个标准的方法来做到这一点? 在iPhone中,这真的很容易。
以下片段只是隐藏键盘:
public static void hideSoftKeyboard(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService( Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( activity.getCurrentFocus().getWindowToken(), 0); }
你可以把它放在一个工具类中,或者如果你在一个活动中定义它,避免活动参数,或者调用hideSoftKeyboard(this)
。
最棘手的部分是何时调用它。 你可以编写一个迭代你的活动中的每个View
的方法, instanceof EditText
如果它没有注册一个setOnTouchListener
到这个组件,并且所有的东西都将落到位,那么检查它是否是instanceof EditText
一个instanceof EditText
。 如果你想知道如何做到这一点,其实很简单。 这里是你所做的,你写了一个像下面这样的recursion方法,事实上你可以用它来做任何事情,比如设置自定义字体等等。下面是方法
public void setupUI(View view) { // Set up touch listener for non-text box views to hide keyboard. if (!(view instanceof EditText)) { view.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { hideSoftKeyboard(MyActivity.this); return false; } }); } //If a layout container, iterate over children and seed recursion. if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { View innerView = ((ViewGroup) view).getChildAt(i); setupUI(innerView); } } }
就是这样,只要在您的活动中设置了内容setContentView
后调用此方法即可。 如果你想知道你将传递什么参数,它是父容器的id
。 指派一个id
给你的父容器
<RelativeLayoutPanel android:id="@+id/parent"> ... </RelativeLayout>
并调用setupUI(findViewById(R.id.parent))
,就是这样。
如果你想有效地使用它,你可以创build一个扩展的Activity
并把这个方法放进去,并且让你的应用程序中的所有其他活动扩展这个活动并在onCreate()
方法中调用它的setupUI()
。
希望它有帮助。
如果你使用多于一个的活动,像<RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>
然后从Activity
扩展一个类并在其OnResume()
定义setupUI(findViewById(R.id.main_parent))
OnResume()
并扩展这个类,而不是in your program
“Activity”
您可以通过执行以下步骤来实现此目的:
-
通过添加以下属性使父视图(您的活动的内容视图)可点击和可聚焦
android:clickable="true" android:focusableInTouchMode="true"
-
实现一个hideKeyboard()方法
public void hideKeyboard(View view) { InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); }
-
最后,设置你的edittext的onFocusChangeListener。
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { hideKeyboard(v); } } });
正如在下面的一个注释中指出的,如果父视图是ScrollView,这可能不起作用。 对于这种情况,可点击和focusableInTouchMode可以直接在ScrollView下添加到视图中。
我发现接受的答案有点复杂。
这是我的解决scheme。 添加一个OnTouchListener
到你的主布局,例如:
findViewById(R.id.mainLayout).setOnTouchListener(this)
并将下面的代码放在onTouch方法中。
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
这样你就不必遍历所有的视图。
我还有一个解决scheme来隐藏键盘:
InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
这里在HIDE_IMPLICIT_ONLY
的位置传递HIDE_IMPLICIT_ONLY
,在HIDE_IMPLICIT_ONLY
的位置showFlag
0
。 它会强制closures软键盘。
那么我设法解决了一些问题,我覆盖了我的活动dispatchTouchEvent,在那里我使用以下来隐藏键盘。
/** * Called to process touch screen events. */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: touchDownTime = SystemClock.elapsedRealtime(); break; case MotionEvent.ACTION_UP: //to avoid drag events if (SystemClock.elapsedRealtime() - touchDownTime <= 150){ EditText[] textFields = this.getFields(); if(textFields != null && textFields.length > 0){ boolean clickIsOutsideEditTexts = true; for(EditText field : textFields){ if(isPointInsideView(ev.getRawX(), ev.getRawY(), field)){ clickIsOutsideEditTexts = false; break; } } if(clickIsOutsideEditTexts){ this.hideSoftKeyboard(); } } else { this.hideSoftKeyboard(); } } break; } return super.dispatchTouchEvent(ev); }
编辑: getFields()方法只是返回一个数组与视图中的文本字段。 为了避免在每次触摸时创build这个数组,我创build了一个名为sFields的静态数组,它在getFields()方法中返回。 这个数组在onStart()方法上初始化,例如:
sFields = new EditText[] {mUserField, mPasswordField};
它不是完美的,拖动事件时间只是基于启发式,所以有时它不会隐藏,当执行长clics,我也完成了创build一个方法来获得所有的editTexts每个视图; 否则键盘会隐藏并显示点击其他EditText时。
尽pipe如此,更清洁和更短的解决scheme,
使用OnFocusChangeListener 。
例如:
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { hideKeyboard(); } } });
更新 :您也可以在您的活动中覆盖onTouchEvent()
并检查触摸的坐标。 如果坐标不在EditText中,则隐藏键盘。
我在Activity中执行dispatchTouchEvent来做到这一点:
private EditText mEditText; private Rect mRect = new Rect(); @Override public boolean dispatchTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); int[] location = new int[2]; mEditText.getLocationOnScreen(location); mRect.left = location[0]; mRect.top = location[1]; mRect.right = location[0] + mEditText.getWidth(); mRect.bottom = location[1] + mEditText.getHeight(); int x = (int) ev.getX(); int y = (int) ev.getY(); if (action == MotionEvent.ACTION_DOWN && !mRect.contains(x, y)) { InputMethodManager input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); input.hideSoftInputFromWindow(mEditText.getWindowToken(), 0); } return super.dispatchTouchEvent(ev); }
我testing它,完美的作品!
我知道这个线程是相当老,正确的答案似乎有效,有很多工作的解决scheme,但我认为下面的方法可能会有更多的效益和优雅的好处。
我需要这种行为,我的所有活动,所以我创build了一个类inheritance自类Activity和“挂钩” dispatchTouchEvent函数的CustomActivity 。 主要有两个条件需要照顾:
- 如果焦点没有改变,并且有人在当前input字段之外轻敲,则closuresIME
- 如果焦点已经改变,下一个焦点元素不是任何typesinput字段的实例,则closuresIME
这是我的结果:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_UP) { final View view = getCurrentFocus(); if(view != null) { final boolean consumed = super.dispatchTouchEvent(ev); final View viewTmp = getCurrentFocus(); final View viewNew = viewTmp != null ? viewTmp : view; if(viewNew.equals(view)) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; view.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); if(rect.contains(x, y)) { return consumed; } } else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) { return consumed; } final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0); viewNew.clearFocus(); return consumed; } } return super.dispatchTouchEvent(ev); }
附注:另外,我将这些属性分配给根视图,可以清除每个input字段的焦点,并防止input字段集中于活动启动(使内容视图成为“焦点捕获器”):
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final View view = findViewById(R.id.content); view.setFocusable(true); view.setFocusableInTouchMode(true); }
我修改了Andre Luis IM的解决scheme,我实现了这个目标:
我创build了一个实用的方法来隐藏软键盘,就像Andre Luiz IM所做的一样:
public static void hideSoftKeyboard(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); }
但是不是为每个视图注册一个OnTouchListener,而是一个糟糕的性能,我只在根视图上注册了OnTouchListener。 由于事件冒泡直到消耗掉(EditText是默认使用它的视图之一),如果它到达根视图,那是因为它没有被使用,所以我closures了软键盘。
findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Utils.hideSoftKeyboard(activity); return false; } });
覆盖任何Activity中的public boolean dispatchTouchEvent(MotionEvent事件)(或扩展Activity类)
@Override public boolean dispatchTouchEvent(MotionEvent event) { View view = getCurrentFocus(); boolean ret = super.dispatchTouchEvent(event); if (view instanceof EditText) { View w = getCurrentFocus(); int scrcoords[] = new int[2]; w.getLocationOnScreen(scrcoords); float x = event.getRawX() + w.getLeft() - scrcoords[0]; float y = event.getRawY() + w.getTop() - scrcoords[1]; if (event.getAction() == MotionEvent.ACTION_UP && (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w.getBottom()) ) { InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0); } } return ret; }
这就是你需要做的
我喜欢调用htafoya制作的dispatchTouchEvent的方法,但是:
- 我不明白计时器部分(不知道为什么要测量停机时间?)
- 我不喜欢用每个视图更改注册/注销所有的EditTexts(可能是相当多的viewchanges和edittexts在复杂的层次结构)
所以,我做了这个更简单的解决scheme:
@Override public boolean dispatchTouchEvent(final MotionEvent ev) { // all touch events close the keyboard before they are processed except EditText instances. // if focus is an EditText we need to check, if the touchevent was inside the focus editTexts final View currentFocus = getCurrentFocus(); if (!(currentFocus instanceof EditText) || !isTouchInsideView(ev, currentFocus)) { ((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE)) .hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } return super.dispatchTouchEvent(ev); } /** * determine if the given motionevent is inside the given view. * * @param ev * the given view * @param currentFocus * the motion event. * @return if the given motionevent is inside the given view */ private boolean isTouchInsideView(final MotionEvent ev, final View currentFocus) { final int[] loc = new int[2]; currentFocus.getLocationOnScreen(loc); return ev.getRawX() > loc[0] && ev.getRawY() > loc[1] && ev.getRawX() < (loc[0] + currentFocus.getWidth()) && ev.getRawY() < (loc[1] + currentFocus.getHeight()); }
有一个缺点:
从一个EditText
切换到另一个EditText
使键盘隐藏和重新显示 – 在我的情况下,这是所需的方式,因为它表明您切换两个input组件。
显示/隐藏软键盘的方法
InputMethodManager inputMethodManager = (InputMethodManager) currentActivity.getSystemService(Context.INPUT_METHOD_SERVICE); if (isShow) { if (currentActivity.getCurrentFocus() == null) { inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } else { inputMethodManager.showSoftInput(currentActivity.getCurrentFocus(), InputMethodManager.SHOW_FORCED); } } else { if (currentActivity.getCurrentFocus() == null) { inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0); } else { inputMethodManager.hideSoftInputFromInputMethod(currentActivity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } }
我希望他们有用
这是另外一个关于fos答案的变体,它解决了sosite引起的问题。
这里的想法是处理Activity的dispatchTouchEvent
方法中的向下和向上的动作。 在向下的动作中,我们logging当前的焦点视图(如果有的话)以及触摸是否在内部,以后保存这些信息。
在上行动作中,我们首先派遣,以允许另一个观点潜在地关注。 如果在此之后,当前的焦点视图就是最初的焦点视图,而向下触摸就是在该视图的内部,那么我们将打开键盘。
如果当前聚焦的视图与最初聚焦的视图不同, 并且它是EditText
,那么我们也将键盘打开。
否则,我们closures它。
所以总结起来,这个工作如下:
- 当触摸当前聚焦的
EditText
,键盘保持打开状态 - 当从关注的
EditText
移动到另一个EditText
,键盘保持打开(不closures/重新打开) - 当触摸不是另一个
EditText
的当前聚焦的EditText
之外的任何地方时,键盘closures - 当长时间按下
EditText
以调出上下文操作栏(使用剪切/复制/粘贴button)时,即使UP操作发生在聚焦的EditText
之外,键盘也保持打开状态(向下移动以腾出空间出租车)。 但请注意,当您点击CAB中的button时,它将closures键盘。 这可能是也可能不是理想的; 如果你想从一个领域剪切/复制并粘贴到另一个领域,这将是。 如果你想粘贴回相同的EditText
,它不会。 -
当聚焦的
EditText
在屏幕的底部,并且你长时间点击一些文本来select它时,EditText
保持焦点,因此键盘打开就像你想要的,因为我们做“触摸在视图范围内”检查下行动作,而不是上行动作。private View focusedViewOnActionDown; private boolean touchWasInsideFocusedView; @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: focusedViewOnActionDown = getCurrentFocus(); if (focusedViewOnActionDown != null) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; focusedViewOnActionDown.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + focusedViewOnActionDown.getWidth(), coordinates[1] + focusedViewOnActionDown.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); touchWasInsideFocusedView = rect.contains(x, y); } break; case MotionEvent.ACTION_UP: if (focusedViewOnActionDown != null) { // dispatch to allow new view to (potentially) take focus final boolean consumed = super.dispatchTouchEvent(ev); final View currentFocus = getCurrentFocus(); // if the focus is still on the original view and the touch was inside that view, // leave the keyboard open. Otherwise, if the focus is now on another view and that view // is an EditText, also leave the keyboard open. if (currentFocus.equals(focusedViewOnActionDown)) { if (touchWasInsideFocusedView) { return consumed; } } else if (currentFocus instanceof EditText) { return consumed; } // the touch was outside the originally focused view and not inside another EditText, // so close the keyboard InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( focusedViewOnActionDown.getWindowToken(), 0); focusedViewOnActionDown.clearFocus(); return consumed; } break; } return super.dispatchTouchEvent(ev); }
它太简单了,只是让你最近的布局点击这个代码的焦点:
android:id="@+id/loginParentLayout" android:clickable="true" android:focusableInTouchMode="true"
然后为该布局编写一个方法和一个OnClickListner,这样当最上面的布局被触及的时候,它将调用一个方法,在这个方法中你将编写代码来closures键盘。 以下是两者的代码; //你必须在OnCreate()中写这个
yourLayout.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { hideKeyboard(view); } });
从listner调用的方法: –
public void hideKeyboard(View view) { InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); }
恳求:我承认我没有影响力,但请认真对待我的回答。
问题:当离开键盘时closures软键盘或用最less的代码编辑文本。
解决scheme:称为Butterknife的外部库。
一线解决scheme:
@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }
更可读的解决scheme:
@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }
说明:将 OnClick Listener绑定到活动的XML布局父级ID,以便任何点击布局(不在编辑文本或键盘上)将运行隐藏键盘的代码片段。
例如:如果你的布局文件是R.layout.my_layout,而你的布局ID是R.id.my_layout_id,那么你的Butterknife绑定调用应该是这样的:
(@OnClick(R.id.my_layout_id) public void yourMethod { InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }
Butterknife文件链接: http ://jakewharton.github.io/butterknife/
插件: Butterknife将彻底改变你的android开发。 考虑一下。
注意:如果不使用外部库Butterknife,也可以获得相同的结果。 如上所述,只需将OnClickListener设置为父布局即可。
有一个更简单的方法,基于iPhone同样的问题。 只需覆盖包含编辑文本的触摸事件的背景布局即可。 只需在活动的OnCreate中使用此代码(login_fondo是根布局):
final LinearLayout llLogin = (LinearLayout)findViewById(R.id.login_fondo); llLogin.setOnTouchListener( new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent ev) { InputMethodManager imm = (InputMethodManager) mActivity.getSystemService( android.content.Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mActivity.getCurrentFocus().getWindowToken(), 0); return false; } });
为了解决这个问题,你必须首先使用EditText的setOnFocusChangeListener
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { Log.d("focus", "focus loosed"); // Do whatever you want here } else { Log.d("focus", "focused"); } } });
然后你需要做的是覆盖dispatchTouchEvent在包含该Edittext的活动中看到下面的代码
@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())) { Log.d("focus", "touchevent"); v.clearFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } } } return super.dispatchTouchEvent(event); }
现在会发生什么是当用户点击外部然后首先dispatchTouchEvent将被调用,然后将清除焦点从editext现在你的OnFocusChangeListener将被调用焦点已被改变现在你可以做任何你想做的事希望它的工作
尝试把stateHidden作为你的活动windowSoftInputMode
值
http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode
例如对于您的活动:
this.getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
这可能是旧的,但我通过实现一个自定义类来得到这个工作
public class DismissKeyboardListener implements OnClickListener { Activity mAct; public DismissKeyboardListener(Activity act) { this.mAct = act; } @Override public void onClick(View v) { if ( v instanceof ViewGroup ) { hideSoftKeyboard( this.mAct ); } } } public void hideSoftKeyboard(Activity activity) { InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); }
这里最好的做法是创build一个Helper类,每个容器的Relative / Linear Layouts应该实现这个。
****注意只有主容器应该实现这个类(为了优化)****
并像这样实现它:
Parent.setOnClickListener( new DismissKeyboardListener(this) );
关键字是用于活动。 所以如果你在片段你使用getActivity();
—竖起大拇指,如果它帮助你… —欢呼拉尔夫—
这是fje的答案略有修改版本,大多完美的工作。
此版本使用ACTION_DOWN,因此执行滚动操作也会closures键盘。 它也不传播事件,除非你点击另一个EditText。 这意味着单击EditText之外的任何地方,即使在另一个可点击的位置,都可以简单地closures键盘。
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_DOWN) { final View view = getCurrentFocus(); if(view != null) { final View viewTmp = getCurrentFocus(); final View viewNew = viewTmp != null ? viewTmp : view; if(viewNew.equals(view)) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; view.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); if(rect.contains(x, y)) { super.dispatchTouchEvent(ev); return true; } } else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) { super.dispatchTouchEvent(ev); return true; } final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0); viewNew.clearFocus(); return true; } } return super.dispatchTouchEvent(ev); }
活动
@Override public boolean dispatchTouchEvent(MotionEvent ev) { ScreenUtils.hideKeyboard(this, findViewById(android.R.id.content).getWindowToken()); return super.dispatchTouchEvent(ev); }
ScreenUtils
public static void hideKeyboard(Context context, IBinder windowToken) { InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS); }
其他的想法是在你的Activity的根视图上覆盖onInterceptTouchEvent
方法。
触摸事件从屏幕上的最前面(触摸事件发生处)沿着视图堆栈向下调用onTouch
方法,直到任何视图返回true,表示触摸事件已被占用。 由于许多视图默认使用触摸事件(例如, EditText
或TextView
),事件不会获取到Activity的根视图onTouch
方法。
但是,在进行遍历之前,触摸事件会沿着另一条path从根视图向下到视图树,直到到达最前面的视图。 This traversal is done by calling onInterceptTouchEvent
. If the method returns true, it intercepts the event… nahhh, but that is a little bit trick, I don't think you want to do that nor to know the details. What you need to know is that you can override this method on the root view for your Activity, and put there the code to hide the keyboard when necessary.
I got this working with a slight variant on Fernando Camarago's solution. In my onCreate method I attach a single onTouchListener to the root view but send the view rather than activity as an argument.
findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { Utils.hideSoftKeyboard(v); return false; } });
In a separate Utils class is…
public static void hideSoftKeyboard(View v) { InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); }
You may easily override the onKey() event in activity and fragments to hide the keyboard.
@Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (keyCode == event.KEYCODE_ENTER) { intiateLoginProcess(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getWindow().getCurrentFocus() .getWindowToken(), 0); return true; } } return false; }
hey guys i have simple solution for this problem and this solution can be used for simple registration or login form. my solution is same as i implemented in ios setontouch listener to Main view
activity_main.xml add ID to your main relative layout android:id="@+id/mainlayout"
and add this code to your activity
RelativeLayout mainLayout = (RelativeLayout)findViewById(R.id.mainlayout); mainLayout.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub Log.d("Json Response", "Touch outside"); InputMethodManager inputMethodManager = (InputMethodManager) MainActivity.this.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), 0); return false; } });
I thought this problem. first, I think that setOnTouchListener is not simple solution. so I believe dispatchTouchEvent is best simple solution.
public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP) { View v = getCurrentFocus(); if (v instanceof EditText) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); } } return super.dispatchKeyEvent(event); }
in here, a important is ACTION_UP.
I assumed EditText only show soft keyboard otherwise not show the keyboard. I have tested on Android5.0.1 (G3.cat6 of LG).
if you need drag checking, long click, …, show comments above.
My solution hides keyboard on outside click in any activity, with of all edit texts. Without specifying them one by one.
First add to root view of layout xml: android:clickable="true" android:focusableInTouchMode="true"
Next, create one parent Acitvity of all activities you want to hide keyboard, and specify onResume() method:
@Override protected void onResume() { super.onResume(); //getting Root View that gets focus View rootView =((ViewGroup)findViewById(android.R.id.content)). getChildAt(0); rootView.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { hideKeyboard(AbstractActivity.this); } } }); }
Extend your activity with this General activity (Inheritance power !) and that's all, every time any EditText (on any extended Activity) will lose focus, keyboard will be hidden.
PS hideKeyboard method :
public static void hideKeyboard(Activity context) { InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( context.getCurrentFocus().getWindowToken(), 0); }
context.getCurrentFocus() doesn't need specifying specific EditText view..
我这样做了:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { View view = getCurrentFocus(); if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) { int scrcoords[] = new int[2]; view.getLocationOnScreen(scrcoords); float x = ev.getRawX() + view.getLeft() - scrcoords[0]; float y = ev.getRawY() + view.getTop() - scrcoords[1]; if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom()) hideKeyboard(this); } return super.dispatchTouchEvent(ev); }
Hide keyboard code :
public static void hideKeyboard(Activity act) { if(act!=null) ((InputMethodManager)act.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((act.getWindow().getDecorView().getApplicationWindowToken()), 0); }
完成
You can try the way below, it works great for me 🙂
This way can be applied for Activity or Fragment and it's also compatible with ScrollView.
We put ScrollView as a top-level layout, declare id parentView for the LinearLayout inside and add two attributes like below:
android:id="@+id/parentView" android:clickable="true" android:focusableInTouchMode="true"
In code, write a function like below:
public static void hideSoftKeyboard (Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); }
Then register an OnFocusChangeListener for the root view (write in onCreate method) to make all EditText in Activity affected:
parentLayout.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { hideSoftKeyboard(your_activity_name.this); } } });
I have refined the method, put the following code in some UI utility class(preferably, not necessarily) so that it can be accessed from all your Activity or Fragment classes to serve its purpose.
public static void serachAndHideSoftKeybordFromView(View view, final Activity act) { if(!(view instanceof EditText)) { view.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { hideSoftKeyboard(act); return false; } }); } if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { View nextViewInHierarchy = ((ViewGroup) view).getChildAt(i); serachAndHideSoftKeybordFromView(nextViewInHierarchy, act); } } } public static void hideSoftKeyboard (Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); }
Then say for example you need to call it from activity, call it as follows;
UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);
注意
findViewById(android.R.id.content)
This gives us the root view of the current group(you mustn't have set the id on root view).
干杯:)