如何隐藏软键盘在android后点击EditText?

每个人都知道要隐藏一个键盘,你需要实现:

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

但这里的大问题是如何隐藏键盘时,用户触摸或选择任何其他地方,不是EditText或softKeyboard?

我尝试在我的父Activity上使用onTouchEvent(),但只有当用户在任何其他视图之外触摸并且没有滚动视图时才有效。

我试图实现一个触摸,点击,焦点监听器,但没有任何成功。

我甚至尝试实现我自己的滚动视图来拦截触摸事件,但我只能得到事件的坐标,而不是视图被单击。

有标准的方法来做这件事吗?在iPhone中,这非常简单。

438114 次浏览

使用OnFocusChangeListener

例如:

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKeyboard();
}
}
});

更新:你也可以在你的活动中覆盖onTouchEvent()并检查触摸的坐标。如果坐标在EditText之外,则隐藏键盘。

另一个想法是在你的Activity的根视图上重写onInterceptTouchEvent方法。

触摸事件从屏幕上最前面的视图(触摸事件发生的地方)开始,沿着调用onTouch方法的视图堆栈向下移动,直到任何视图返回true,表明触摸事件已被消费。由于许多视图在默认情况下使用触摸事件(例如,EditTextTextView的情况),事件不会到达活动的根视图onTouch方法。

但是,在这个遍历之前,触摸事件移动了另一条路径,从根视图向下到视图树,直到它到达最前面的视图。遍历是通过调用onInterceptTouchEvent来完成的。如果该方法返回true,它将拦截事件…嗯,但这是一个小技巧,我认为你不想这样做,也不想知道细节。您需要知道的是,您可以在Activity的根视图上覆盖这个方法,并在必要时将代码放在那里以隐藏键盘。

尝试将stateHidden作为你的活动windowSoftInputMode

http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode

例如你的活动:

this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

好吧,我设法某种程度上解决了这个问题,我在我的活动上覆盖了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()方法只是一个返回视图中包含文本字段的数组的方法。为了避免每次触摸都创建这个数组,我创建了一个名为sFields的静态数组,它在getFields()方法中返回。该数组在onStart()方法上初始化,例如:

sFields = new EditText[] {mUserField, mPasswordField};


它不是完美的,拖动事件时间只是基于启发式,所以有时它不会隐藏在执行长clics时,我也完成了创建一个方法来获得每个视图的所有editTexts;否则,当单击其他EditText时,键盘将隐藏和显示。

不过,更干净、更短的解决方案还是受欢迎的

我有一个解决方案来隐藏键盘:

InputMethodManager imm = (InputMethodManager) getSystemService(
Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
这里传递HIDE_IMPLICIT_ONLYshowFlag的位置,传递0hiddenFlag的位置。

.关闭软键盘

有一个更简单的方法,基于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;
}
});

下面的代码片段只是隐藏了键盘:

public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager =
(InputMethodManager) activity.getSystemService(
Activity.INPUT_METHOD_SERVICE);
if(inputMethodManager.isAcceptingText()){
inputMethodManager.hideSoftInputFromWindow(
activity.getCurrentFocus().getWindowToken(),
0
);
}
}

你可以把它放在一个实用程序类中,或者如果你在一个活动中定义它,避免使用活动参数,或者调用hideSoftKeyboard(this)

最棘手的部分是何时调用它。你可以编写一个方法,遍历活动中的每一个View,并检查它是否为instanceof EditText,如果它没有注册setOnTouchListener到该组件,一切都将到位。如果你想知道如何做到这一点,实际上很简单。这就是你要做的,你写一个像下面这样的递归方法,事实上你可以用它来做任何事情,比如设置自定义字体等…这是方法

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)),仅此而已。

如果你想有效地使用它,你可以创建一个扩展的Activity并把这个方法放进去,并让应用程序中的所有其他活动扩展这个活动并在onCreate()方法中调用它的setupUI()

希望能有所帮助。

如果你使用超过1个活动定义公共id到父布局,如 <RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout> < / p >

然后从Activity扩展一个类,并在其OnResume()中定义setupUI(findViewById(R.id.main_parent)),并扩展这个类而不是' ' Activity in your program


下面是上面函数的Kotlin版本:

@file:JvmName("KeyboardUtils")


fun Activity.hideSoftKeyboard() {
currentFocus?.let {
val inputMethodManager = ContextCompat.getSystemService(this, InputMethodManager::class.java)!!
inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0)
}
}

显示/隐藏软键盘的方法

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


}

我希望它们对你有用

我修改了Andre Luis IM的解决方案,我做到了这一点:

我创建了一个实用工具方法来隐藏软键盘,就像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是默认消费它的视图之一),如果它到达根视图,那是因为它没有被消费,所以我关闭软键盘。

findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Utils.hideSoftKeyboard(activity);
return false;
}
});

我得到了这个工作与费尔南多卡马拉戈的解决方案略有不同。在我的onCreate方法中,我附加了一个onTouchListener到根视图,但将视图而不是活动作为参数发送。

        findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
Utils.hideSoftKeyboard(v);
return false;
}
});

在一个单独的Utils类中是…

    public static void hideSoftKeyboard(View v) {
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}

我喜欢htafoya调用dispatchTouchEvent的方法,但是:

  • 我不理解定时器的部分(不知道为什么测量停机时间应该是必要的?)
  • 我不喜欢注册/取消注册所有的EditTexts与每一个视图的变化(可能是相当多的视图变化和编辑文本在复杂的层次结构)

所以,我做了一个更简单的解决方案:

@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会使键盘隐藏并重新显示——在我的例子中,这是理想的方式,因为它显示你在两个输入组件之间切换。

我知道这个线程是相当古老的,正确的答案似乎是有效的,有很多工作的解决方案,但我认为下面所述的方法可能有一个额外的好处,关于效率和优雅。

我的所有活动都需要这种行为,所以我创建了一个类CustomActivity,继承了类活动,并“钩住”了dispatchTouchEvent函数。主要有两个条件需要注意:

  1. 如果焦点没有改变,并且有人在当前输入域之外轻敲,则忽略输入法
  2. 如果焦点已经改变,并且下一个焦点元素不是任何类型的输入字段的实例,则驳回IME

这是我的结果:

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

附注:另外,我将这些属性分配给根视图,使它能够清除每个输入字段的焦点,并防止输入字段获得活动启动的焦点(使内容视图为“焦点捕获器”):

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


final View view = findViewById(R.id.content);


view.setFocusable(true);
view.setFocusableInTouchMode(true);
}

我觉得公认的答案有点复杂。

这是我的解决方案。在主布局中添加OnTouchListener,即:

findViewById(R.id.mainLayout).setOnTouchListener(this)

并将以下代码放入onTouch方法中。

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

这样就不必遍历所有视图。

你可以通过以下步骤来实现这一点:

  1. 通过添加以下属性使父视图(您的活动的内容视图)可单击和可聚焦

        android:clickable="true"
    android:focusableInTouchMode="true"
    
  2. Implement a hideKeyboard() method

        public void hideKeyboard(View view) {
    InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }
    
  3. Lastly, set the onFocusChangeListener of your edittext.

        edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
    if (!hasFocus) {
    hideKeyboard(v);
    }
    }
    });
    

As pointed out in one of the comments below, this might not work if the parent view is a ScrollView. For such case, the clickable and focusableInTouchMode may be added on the view directly under the ScrollView.

你可以很容易地覆盖onKey()事件在活动和片段隐藏键盘。

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

嘿,伙计们,我有这个问题的简单解决方案,这个解决方案可以用于简单的注册或登录形式。 我的解决方案与我在ios setontouch监听主视图

中实现的解决方案相同

添加ID到你的主相对布局android:id="@+id/mainlayout"

并将此代码添加到您的活动中

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

我在活动中实现了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);
}

我测试过了,效果完美!

在任何活动(或扩展类活动)中覆盖公共布尔dispatchTouchEvent(MotionEvent事件)

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

芬兰湾的科特林版:

 override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
val ret = super.dispatchTouchEvent(ev)
ev?.let { event ->
if (event.action == MotionEvent.ACTION_UP) {
currentFocus?.let { view ->
if (view is EditText) {
val touchCoordinates = IntArray(2)
view.getLocationOnScreen(touchCoordinates)
val x: Float = event.rawX + view.getLeft() - touchCoordinates[0]
val y: Float = event.rawY + view.getTop() - touchCoordinates[1]
//If the touch position is outside the EditText then we hide the keyboard
if (x < view.getLeft() || x >= view.getRight() || y < view.getTop() || y > view.getBottom()) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
view.clearFocus()
}
}
}
}
}
return ret
}

这就是你需要做的

这可能是旧的,但我得到了这个工作通过实现一个自定义类

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

这里的最佳实践是创建一个Helper类,每个容器相对/线性布局都应该实现这个。

****注意只有主容器应该实现这个类(为了优化)****

并像这样实现它:

Parent.setOnClickListener( new DismissKeyboardListener(this) );

关键字这是为活动。如果你在fragment上,你可以使用getActivity();

-大拇指如果它对你有帮助… ——干杯,拉尔夫——

我认为这个问题。 首先,我认为setOnTouchListener不是一个简单的解决方案。 所以我认为dispatchTouchEvent是最好的简单解决方案
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);
}

这里,重要的是ACTION_UP。

我假设EditText只显示软键盘,否则不显示键盘。 我已经在Android5.0.1 (G3。LG的cat6).

如果你需要拖拽检查,长按…,显示上面的评论。

这是对fje的答案稍加修改的版本,这个答案基本上非常有效。

这个版本使用ACTION_DOWN,所以执行滚动动作也会关闭键盘。 它也不会传播事件,除非您单击另一个EditText。这意味着点击EditText以外的任何地方,即使是在另一个可点击的地方,也只是关闭键盘

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

下面是fje回答的另一个变体,它解决了sosite提出的问题。

这里的思想是在Activity的dispatchTouchEvent方法中处理向下和向上操作。在按下操作时,我们会记录当前聚焦的视图(如果有的话),以及触摸是否在其中,并为以后保存这两个信息。

在向上操作中,我们首先分派,以允许另一个视图潜在地获得焦点。如果在那之后,当前聚焦的视图是最初聚焦的视图,向下触摸在那个视图内,然后我们让键盘打开。

如果当前聚焦的视图与最初聚焦的视图而且不同,它是EditText,那么我们也让键盘打开。

否则我们关闭它。

综上所述,其工作原理如下:

  • 当触摸到当前聚焦的EditText内部时,键盘保持打开
  • 当从一个聚焦的EditText移动到另一个EditText时,键盘保持打开(不关闭/重新打开)
  • 当触摸当前聚焦的EditText以外的任何地方,而不是另一个EditText时,键盘关闭
  • 当长按EditText以调出上下文操作栏(带有剪切/复制/粘贴按钮)时,键盘保持打开,即使up操作发生在被聚焦的EditText之外(向下移动为CAB腾出空间)。但是请注意,当您点击CAB中的一个按钮时,它将关闭键盘。这可能是可取的,也可能不是;如果你想从一个字段剪切/复制并粘贴到另一个字段,它将是。如果你想粘贴回相同的EditText,它将不会。
  • 当被聚焦的EditText位于屏幕底部,并且你长时间点击一些文本来选择它时,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);
    }
    

我的解决方案隐藏键盘在外面点击任何活动,与所有编辑文本。没有一一说明。

首先添加到布局xml的根视图: android:点击= " true " android: focusableInTouchMode = " true " < / p >

接下来,创建一个你想隐藏键盘的所有活动的父活动,并指定onResume()方法:

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

用这个General activity(继承能力!)扩展你的活动,就是这样,每次任何EditText(在任何扩展的活动上)将失去焦点,键盘将被隐藏。

附注:hideKeyboard方法:

public static void hideKeyboard(Activity context) {
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow( context.getCurrentFocus().getWindowToken(), 0);
}

context.getCurrentFocus()不需要指定特定的EditText视图..

我是这样做的:

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

隐藏键盘代码:

public static void hideKeyboard(Activity act) {
if(act!=null)
((InputMethodManager)act.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((act.getWindow().getDecorView().getApplicationWindowToken()), 0);
}

完成

要解决这个问题,你必须首先使用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在活动中包含的编辑文本见下面的代码

@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会被调用它会从编辑文本中清除焦点现在你的OnFocusChangeListener会被调用焦点已经改变了现在在这里你可以做任何你想做的希望它能起作用

你可以试试下面的方法,它对我很有用:)

这种方式可以应用于活动或片段,它也与ScrollView兼容。

我们将ScrollView作为顶级布局,在LinearLayout中声明id parentView,并添加如下两个属性:

android:id="@+id/parentView"
android:clickable="true"
android:focusableInTouchMode="true"

在代码中,编写如下函数:

public static void hideSoftKeyboard (Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}

然后为根视图注册一个OnFocusChangeListener(写入onCreate方法),使Activity中的所有EditText受到影响:

parentLayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
hideSoftKeyboard(your_activity_name.this);
}
}
});

我已经改进了方法,把下面的代码放在一些UI实用工具类(最好,不一定),这样它可以从所有的活动或片段类访问,以达到它的目的。

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

然后假设你需要从activity中调用它,像这样调用;

UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);

请注意

findViewById (android.R.id.content)

这给了我们当前组的根视图(你不能在根视图上设置id)。

欢呼:)

它太简单了,只是让你最近的布局点击一个可聚焦的代码:

android:id="@+id/loginParentLayout"
android:clickable="true"
android:focusableInTouchMode="true"

,然后为该布局写一个方法和一个OnClickListner,这样当最上面的布局被触及时,它将调用一个方法,在这个方法中你将编写代码来消除键盘。以下是两者的代码; //你必须写在OnCreate()

 yourLayout.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
hideKeyboard(view);
}
});

从侦听器调用的方法:-

 public void hideKeyboard(View view) {
InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.
INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
return true;
}
setupUI((RelativeLayout) findViewById(R.id.activity_logsign_up_RelativeLayout));
将方法传递到布局文件中。您必须选择常用的XML布局文件。 因为,键盘隐藏适用于整个布局
public void setupUI(View view) {
// Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(Your Context); // Pass your context
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);
}
}
}

我设法隐藏键盘从onItemClick AutoCompleteTextView

public void onItemClick(AdapterView<?> adapterViewIn, View viewIn, int indexSelected, long arg3) {
InputMethodManager imm = (InputMethodManager) getSystemService(viewIn.getContext().INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(viewIn.getApplicationWindowToken(), 0);
// your code HERE
}

我知道我没有影响力,但请认真对待我的回答。

问题:关闭软键盘时,点击键盘或编辑文本与最小的代码。

解决方案:外部库称为Butterknife。

一句话解决方案:

@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }

更具可读性的解决方案:

@OnClick(R.id.activity_signup_layout)
public void closeKeyboard() {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}

绑定OnClick监听器到活动的XML布局父ID,这样在布局上的任何点击(不是在编辑文本或键盘上)都将运行将隐藏键盘的代码片段。

例子:如果你的布局文件是R.layout。my_layout,你的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到上面描述的父布局。

你可以使用这段代码,使用你的主布局Id而不是"mainRelativeLayout"

//hide Soft keyboard on click outside  the input text
findViewById(R.id.mainRelativeLayout).setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
InputMethodManager im = (InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
im.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
0);
}


});

活动

 @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);
}
只需在类中添加此代码 @Overide < / p >
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())
((InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((this.getWindow().getDecorView().getApplicationWindowToken()), 0);
}
return super.dispatchTouchEvent(ev);
}

一个更芬兰湾的科特林 &使用TextInputEditText材料设计方式(此方法也兼容EditTextView)…

1.通过添加以下属性,使父视图(您的活动/片段的内容视图)可单击和可聚焦

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

2.为所有View创建一个扩展(在ViewExtension内)。Kt文件为例):

fun View.hideKeyboard(){
val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(this.windowToken, 0)
}

3.创建一个继承了TextInputEditText的BaseTextInputEditText。实现onFocusChanged方法在视图未聚焦时隐藏键盘:

class BaseTextInputEditText(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs){
override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
super.onFocusChanged(focused, direction, previouslyFocusedRect)
if (!focused) this.hideKeyboard()
}
}

4.只需在XML中调用全新的自定义视图:

<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayout"
...>


<com.your_package.BaseTextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
... />


</android.support.design.widget.TextInputLayout>

这是所有。不需要修改控制器(片段或活动)来处理这种重复的情况。

对于这个简单的要求,我发现公认的答案有点复杂。以下是对我有效的方法,没有任何故障。

findViewById(R.id.mainLayout).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
return false;
}
});

只需在活动中覆盖下面的代码

 @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (getCurrentFocus() != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
return super.dispatchTouchEvent(ev);
}

更新:

如果有人需要这个答案的Kotlin版本:

override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (currentFocus != null) {
val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(activity!!.currentFocus!!.windowToken, 0)
}
return super.dispatchTouchEvent(ev)
}

这对我来说是最简单的解决方案(也是我自己想出的)。

这是隐藏键盘的方法。

public void hideKeyboard(View view){
if(!(view instanceof EditText)){
InputMethodManager inputMethodManager=(InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
}
}

现在将活动的父布局的onclick属性设置为上面的方法hideKeyboard,无论是从XML文件的设计视图还是在XML文件的文本视图中编写下面的代码。

android:onClick="hideKeyboard"

在kotlin中,我们可以执行以下操作。不需要迭代所有视图。它也适用于片段。

override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
currentFocus?.let {
val imm: InputMethodManager = getSystemService(
Context.INPUT_METHOD_SERVICE
) as (InputMethodManager)
imm.hideSoftInputFromWindow(it.windowToken, 0)
}
return super.dispatchTouchEvent(ev)
}

你可以实现View。onClickListener和重写onClick方法,并将这个onClickListener设置为布局

ConstraintLayout constraintLayout;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.layout);
constraintLayout.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v.getId()==R.id.layout){
InputMethodManager inm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
inm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
}
}

加上之前的@sumit sonawane的答案,这个解决方案不会在用户滚动时隐藏键盘。

public long pressTime = 0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
pressTime = System.currentTimeMillis();
}
else if (ev.getAction() == MotionEvent.ACTION_UP) {
long releaseTime = System.currentTimeMillis();
if (releaseTime-pressTime < 200) {
if (getCurrentFocus() != null) {
GhostTube.print("BottomNavActivity", "Touch event with keyboard detected...");
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(ev);
}

添加代码到您的活动,也将照顾片段。

而不是遍历所有视图或重写dispatchTouchEvent。

为什么不重写onUserInteraction()的活动,这将确保键盘解散每当用户点击EditText之外。

即使EditText在scrollView中也能工作。

@Override
public void onUserInteraction() {
if (getCurrentFocus() != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}

我稍微修改了一下@ navneth -g的答案,增加了null活动焦点处理,避免了创建OnTouchListener的多个实例,键盘隐藏时删除焦点,屏幕滚动时删除隐藏键盘,在小设备上方便。

//In general, the view parameter is root layout
fun Activity.hideKeyboardOnClickOutsideEditText(view: View) {
// Set up touch listener for non-text box views to hide keyboard.
var previousAction = 0
val onTouchListener = View.OnTouchListener { v, event ->
if (currentFocus != null
&& event.action != MotionEvent.ACTION_DOWN
&& event.action != MotionEvent.ACTION_MOVE
&& previousAction != MotionEvent.ACTION_MOVE
) {
currentFocus?.clearFocus()
v?.hideKeyboard()
}
previousAction = event.action
false
}


if (view !is EditText) {
view.setOnTouchListener(onTouchListener)
}


//If a layout container, iterate over children and seed recursion.
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val innerView = view.getChildAt(i)
hideKeyboardOnClickOutsideEditText(innerView)
}
}
}
   

//in root layout.xml
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"

唯一有效的代码

private var viewHeight = 0


private fun setRootViewListener() {
binding.root.apply {
viewTreeObserver.addOnGlobalLayoutListener {
viewHeight = height
}
}
}


override fun dispatchTouchEvent(event: MotionEvent): Boolean {
currentFocus?.let {
if (it is EditText && event.y < viewHeight - it.measuredHeight) {
hideKeyboard(it)
}
}
return super.dispatchTouchEvent(event)
}
非常困难的决定。我建议一个更简单的解决办法。 在onViewCreated中,我们为整个视图设置了一个setOnClickListener,并从EditText中删除焦点,以及删除键盘

片段中的例子。Java。

@Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);


nameTextInputEditText = view.findViewById(R.id.NameTextInputEditText);


view.setOnClickListener(v -> {
nameTextInputEditText.clearFocus();


InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
});
}

对于那些正在为此寻找Xamarin代码的人,请访问:

  public override bool DispatchTouchEvent(MotionEvent ev)
{
try
{
View view = CurrentFocus;
if (view != null && (ev.Action == MotionEventActions.Up || ev.Action == MotionEventActions.Move) && view is EditText && !view.Class.Name.StartsWith("android.webkit."))
{
int[] Touch = new int[2];
view.GetLocationOnScreen(Touch);
float x = ev.RawX + view.Left - Touch[0];
float y = ev.RawY + view.Top - Touch[1];
if (x < view.Left || x > view.Right || y < view.Top || y > view.Bottom)
((InputMethodManager)GetSystemService(InputMethodService)).HideSoftInputFromWindow((Window.DecorView.ApplicationWindowToken), 0);
}
}
catch (System.Exception ex)
{
           

}


return base.DispatchTouchEvent(ev);
}

在Manifest中输入:android:windowSoftInputMode="stateHidden"就像这样

<activity
android:name=".MainActivity"
android:exported="false"
android:windowSoftInputMode="stateHidden" />

对于这个问题,我有一个简单的解决方案:

InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);