Как скрыть мягкую клавиатуру на android после нажатия за пределами EditText?

Ok все знают, что чтобы скрыть клавиатуру, вам нужно реализовать:

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

но большое дело здесь, как скрыть клавиатуру, когда пользователь касается или выбирает любое другое место, которое не является EditText или softKeyboard?

Я попытался использовать onTouchEvent() на моих родителей Activity но это работает только в том случае, если пользователь касается вне любого другого представления и нет scrollview.

Я попытался реализовать touch, click, focus listener без каких-либо успех.

Я даже пытался реализовать свой собственный scrollview для перехвата сенсорных событий, но я могу получить только координаты события,а не вид щелкнул.

есть ли стандартный способ сделать это?? в iPhone это было очень просто.

30 ответов


следующий фрагмент просто скрывает клавиатуру:

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

вы можете поместить это в класс утилиты, или если вы определяете его в activity, избегайте параметра activity или вызовите 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 и поместите этот метод В, и сделать все другие действия в вашем приложении расширить эту деятельность и вызвать его setupUI() на onCreate() метод.

надеюсь, что это помогает.

если вы используете более 1 действия, определите общий id для родительского макета, например <RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>

затем расширьте класс от Activity и определить setupUI(findViewById(R.id.main_parent)) в своем OnResume() и расширить этот класс вместо " Activityin your program


вы можете добиться этого, выполнив следующие действия:

  1. сделайте родительское представление (представление содержимого вашей деятельности) кликабельным и фокусируемым, добавив следующие атрибуты

        android:clickable="true" 
        android:focusableInTouchMode="true" 
    
  2. реализовать метод hideKeyboard ()

        public void hideKeyboard(View view) {
            InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    
  3. наконец, установите onFocusChangeListener вашего edittext.

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

как отметил в одном из комментариев ниже, это может не сработать, если родительское представление-это ScrollView. В таком случае, clickable и focusableInTouchMode могут быть добавлены в представлении непосредственно под ScrollView.


Я нахожу принятый ответ немного сложным.

вот мое решение. Добавить OnTouchListener к вашему основному макету, т. е.:

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

и поместите следующий код в методе onTouch.

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

таким образом, вам не нужно перебирать все представления.


у меня есть еще одно решение, чтобы скрыть клавиатуру:

InputMethodManager imm = (InputMethodManager) getSystemService(
    Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);

здесь проходят HIDE_IMPLICIT_ONLY в должности showFlag и 0 в должности hiddenFlag. Он принудительно закроет мягкую клавиатуру.


Ну, мне удается несколько решить проблему, я преодолел 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);
}

EDIT: метод getFields () - это просто метод, который возвращает массив с текстовыми полями в представлении. Чтобы избежать создания этого массива при каждом касании, я создал статический массив sFields, который возвращается методом getFields (). Этот массив инициализируется в методе onStart() методы as:

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


это не идеально, время события перетаскивания основано только на эвристике, поэтому иногда оно не скрывается при выполнении длинных кликов, и я также закончил, создав метод, чтобы получить все editTexts за представление; иначе клавиатура будет скрывать и показывать при нажатии другого EditText.

тем не менее, более чистые и короткие решения приветствуются


использовать OnFocusChangeListener.

например:

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

обновление: вы также можете переопределить onTouchEvent() в вашей деятельности и проверьте координаты касания. Если координаты находятся вне EditText, то скройте клавиатуру.


я реализовал 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);
}

и я протестировал его, работает отлично!


переопределить public boolean 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;
}

и это все, что вам нужно сделать


Я знаю, что эта тема довольно старая, правильный ответ кажется действительным, и есть много рабочих решений, но я думаю, что подход, изложенный ниже, может иметь дополнительное преимущество в отношении эффективности и элегантности.

мне нужно это поведение для всех моих действий, поэтому я создал класс CustomActivity наследование от класса активность и "сажают"dispatchTouchEvent


Я изменил решение Андре Луиса IM я достиг этого:

Я создал метод утилиты, чтобы скрыть мягкую клавиатуру так же, как Андре Луис 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;
    }
});

мне понравился подход вызова dispatchTouchEvent сделано htafoya, но:

  • Я не понял часть таймера (не знаю, почему измерение времени простоя должно быть необходимо?)
  • мне не нравится регистрировать / отменять регистрацию всех EditTexts с каждым изменением представления (может быть довольно много viewchanges и 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 делает клавиатуру скрыть и изменить-в моем случае это желательно, потому что это показывает, что вы переключились между двумя входными компонентами.


просьба: Я признаю, что у меня нет влияния, но, пожалуйста, отнеситесь к моему ответу серьезно.

: закрыть экранную клавиатуру при нажатии кнопки от клавиатуры или редактировать текст с минимальным кодом.

устранение: внешняя библиотека, известная как 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-макета действия, чтобы любой щелчок по макету (не на редактируемом тексте или клавиатуре) запускал этот фрагмент кода, который скроет клавиатуру.

пример: если ваш файл макета R. layout.my_layout и Ваш идентификатор макета-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 в родительский макет, как описано выше.


метод отображения / скрытия мягкой клавиатуры

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

    }

надеюсь, они были полезны


вот еще один вариант ответа fje, который касается вопросов, поднятых sosite.

идея здесь состоит в том, чтобы обрабатывать как вниз, так и вверх действия в dispatchTouchEvent метод. В действии вниз мы отмечаем текущее сфокусированное представление (если есть) и было ли прикосновение внутри него, сохраняя оба этих бита информации на потом.

на действие up, Мы сначала отправляем, чтобы позволить другому взгляду потенциально сосредоточиться. Если после этого в настоящее время сфокусированный вид-это первоначально сфокусированный вид, и касание вниз было внутри этого вида, затем мы оставляем клавиатуру открытой.

если текущий сфокусированный вид отличается от первоначально сфокусированного вида и это EditText, затем мы также оставляем клавиатуру открытой.

в противном случае мы закроем его.

Итак, подводя итог, это работает следующим образом:

  • при касании внутри в настоящее время сосредоточены EditText клавиатура остается открыть
  • при движении от сфокусированного EditText в другой EditText, клавиатура остается открытой (не закрывается/не открывается)
  • при прикосновении в любом месте за пределами в настоящее время сосредоточены EditText это не другой EditText клавиатура закрывает
  • при длительном нажатии в EditText чтобы вызвать контекстную панель действий (с кнопками вырезать/копировать/вставить), клавиатура остается открытой, даже если действие вверх имело место вне сфокусированного EditText (который двинулся вниз, чтобы сделать место для такси). Обратите внимание, что при нажатии на кнопку в кабине, он закроет клавиатуру. Это может быть или не быть желательным; если вы хотите вырезать/скопировать из одного поля и вставить в другое, это будет. Если вы хотите вставить обратно в то же самое EditText, это не будет.
  • когда вопрос EditText в нижней части экрана, и вы долго-нажмите на текст, чтобы выбрать его,EditText держит фокус и поэтому клавиатура открывается, как вы хотите, потому что мы делаем проверка" touch is within view bounds " на действии вниз, а не вверх.

    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 для этого макета, так что, когда верхний макет коснется любого места, он вызовет метод, в котором вы напишете код для отклонения клавиатуры. ниже приведен код для обоих; // вы должны написать это в 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);
    }

есть более простой подход, основанный на той же проблемы на 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;
                }
            });

я усовершенствовал метод, поместил следующий код в некоторый класс утилиты 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.содержание)

это дает нам корневое представление текущей группы(не установите идентификатор в корневом представлении).

Ура :)


попробуйте поставить stateHidden в качестве вашей деятельности windowSoftInputMode стоимостью

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

например для вашей деятельности:

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

активность

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

более Котлин & Материал Дизайн способ использования TextInputEditText (этот подход также согласуется с EditTextView)...

1.Сделайте родительское представление (представление содержимого вашей активности/фрагмента) кликабельным и фокусируемым, добавив следующие атрибуты

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

2.Создайте расширение для всего представления (внутри ViewExtension.файл КТ например) :

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

3.Создать BaseTextInputEditText, которые наследуют TextInputEditText. Реализуйте метод 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;
        }
    });

Это может быть старым, но я получил эту работу, добавив пользовательский класс

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

рекомендуется создать вспомогательный класс, и каждый относительный / линейный макет контейнера должен реализовать это.

* * * * обратите внимание, что только основной контейнер должен реализовать этот класс (для оптимизации) ****

и реализовать его следующим образом:

Parent.setOnClickListener( new DismissKeyboardListener(this) ); 

ключевое слово это для Activity. поэтому, если вы находитесь на фрагменте, вы используете like getActivity();

---пальцы вверх если это поможет вам... --- ура Ральф ---


Это слегка измененная версия ответа 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);
}

Я сделал так:

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

сделал


чтобы решить эту проблему, вам нужно сначала использовать setOnFocusChangeListener этого Edittext

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 см. ниже code

@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 будет вызван, что фокус был изменено теперь здесь вы можете сделать все, что вы хотели сделать надеюсь, что это работает


@Override
    public boolean onTouchEvent(MotionEvent event) {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.
                INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        return true;
    }

другая идея-переопределить onInterceptTouchEvent метод в корневом представлении для вашей деятельности.

событие касания идет от самого переднего вида на экране (где произошло событие касания) вниз по стеку представлений, вызывающих onTouch метод до тех пор, пока любое из представлений не вернет true, указывая, что событие касания было потреблено. Поскольку многие из представлений по умолчанию потребляют событие touch (Это относится к EditText или TextView, например), событие не попадает в корневое представление действия onTouch метод.

но, прежде чем сделать этот обход, событие касания перемещается по другому пути, идя от корневого вида вниз по дереву вида, пока не доберется до самого переднего вида. Этот обход выполняется путем вызова onInterceptTouchEvent. Если метод возвращает true, он перехватывает событие... Неа, но это небольшой трюк, я не думаю, что ты хочешь это делать или знать детали. Что вам нужно знать, так это то, что вы можете переопределить этот метод в корневом представлении для своей деятельности и поместить туда код для скрытия клавиатуры при необходимости.


Я получил эту работу с легким вариантом на решение Фернандо Camarago это. В моем методе 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);
}

вы можете легко переопределить событие onKey () в activity и фрагментах, чтобы скрыть клавиатуру.

@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 listener для Main view

activity_main.xml добавить 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;
            }
        });