Как скрыть мягкую клавиатуру на андроиде, щелкнув вне EditText?

Хорошо, все знают, что для скрытия клавиатуры вам нужно реализовать:

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

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

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

Я попытался реализовать прикосновение, щелчок, прослушиватель фокуса без каких-либо успехов.

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

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

Ответ 1

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

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

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().

Надеюсь, что это поможет.

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

Затем продолжите класс из Activity и определите setupUI(findViewById(R.id.main_parent)) В пределах его OnResume() и продолжите этот класс вместо `` Activity in your program

Ответ 2

Это можно сделать, выполнив следующие шаги:

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

        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);
        }
    
  • Наконец, установите onFocusChangeListener вашего edittext.

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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


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

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

Ответ 6

Просто переопределите код ниже в Activity

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

Ответ 7

Используйте OnFocusChangeListener.

Например:

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

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

Ответ 8

Я выполнил dispatchTouchEvent в Activity, чтобы сделать это:

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

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

Ответ 9

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

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

Ответ 10

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

Мне нужно это поведение для всех моих действий, поэтому я создал класс CustomActivity, наследующий от класса Activity, и "подключил" функцию dispatchTouchEvent. В основном есть два условия:

  • Если фокус не изменился, и кто-то выстукивает за пределами текущего поля ввода, затем отпустите IME
  • Если фокус изменился, и следующий сфокусированный элемент не является экземпляром какого-либо поля ввода, затем отпустите 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);
}

Ответ 11

Более удобный способ Kotlin & Material Design с использованием 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. Создайте 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> 

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

Ответ 12

Я изменил решение 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;
    }
});

Ответ 13

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

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

Ответ 14

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

Проблема: Отключите мягкую клавиатуру при нажатии на клавиатуре или редактировании текста с минимальным кодом.

Решение: Внешняя библиотека, известная как 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/

Plug: Butterknife произведет революцию в развитии Android. Подумайте об этом.

Примечание: Тот же результат может быть достигнут без использования внешней библиотеки Butterknife. Просто установите OnClickListener в родительский макет, как описано выше.

Ответ 15

Вот еще одна вариация ответа 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);
    }
    

Ответ 16

слишком просто, просто сделайте свой недавний макет кликабельным с помощью этого кода:

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

Ответ 17

Для этого простого требования я нашел принятый ответный бит. Здесь то, что сработало для меня без каких-либо сбоев.

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

Ответ 18

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

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

    }

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

Ответ 20

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

Ответ 21

Я уточнил метод, поместил следующий код в некоторый класс утилиты UI (желательно, не обязательно), чтобы он мог быть доступен из всех классов Activity или Fragment, чтобы служить его цели.

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

Тогда скажите, например, вам нужно вызвать его из операции, назовите его следующим образом:

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

Примечание

findViewById (android.R.id.content)

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

Приветствия:)

Ответ 22

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

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, и каждый контейнер Relative/Linear Layouts должен реализовать это.

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

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

Parent.setOnClickListener( new DismissKeyboardListener(this) ); 

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

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

Ответ 23

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

Ответ 24

Я сделал так:

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

Готово

Ответ 25

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

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

Ответ 26

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

Ответ 27

Ну, вы можете использовать этот код, используйте свой основной макет, а не "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);
        }

    });

Ответ 28

Деятельность

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

Ответ 29

Просто добавьте этот код в класс  @Overide

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

Ответ 30

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