Закройте / спрячьте мягкую клавиатуру Android


14 Answers

Чтобы помочь прояснить это безумие, я хотел бы начать с извинения от имени всех пользователей Android за простое смешное обращение с Google к мягкой клавиатуре. Причина в том, что так много ответов, по-разному, по одному и тому же вопросу, потому что этот API, как и многие другие в Android, ужасно разработан. Я не могу придумать ни одного вежливого способа заявить об этом.

Я хочу скрыть клавиатуру. Я ожидаю, что Android предоставит следующее заявление: Keyboard.hide() . Конец. Большое спасибо. Но у Android есть проблемы. Вы должны использовать InputMethodManager чтобы скрыть клавиатуру. Хорошо, отлично, это API Android на клавиатуре. НО! У вас должен быть Context , чтобы получить доступ к IMM. Теперь у нас есть проблема. Я могу скрыть клавиатуру от статического или служебного класса, который не нужен или нужен для любого Context . или И еще хуже, IMM требует, чтобы вы указали, какой View (или, что еще хуже, какой Window ) вы хотите скрыть клавиатуру FROM.

Это то, что скрывает клавиатуру так сложно. Дорогой Google: Когда я ищу рецепт для пирога, на Земле нет RecipeProvider , который откажется предоставить мне рецепт, если я не отвечу сначала, что торт будет съеден И где он будет съеден !!

Эта печальная история заканчивается уродливой правдой: чтобы скрыть клавиатуру Android, вам потребуется предоставить две формы идентификации: Context и либо View либо Window .

Я создал статический метод утилиты, который может выполнять работу ОЧЕНЬ солидно, если вы вызываете его из Activity .

public static void hideKeyboard(Activity activity) {
    InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    //Find the currently focused view, so we can grab the correct window token from it.
    View view = activity.getCurrentFocus();
    //If no view currently has focus, create a new one, just so we can grab a window token from it
    if (view == null) {
        view = new View(activity);
    }
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

Имейте в виду, что этот метод утилиты ТОЛЬКО работает при вызове из Activity ! Вышеуказанный метод вызывает getCurrentFocus целевого Activity для получения правильного токена окна.

Но предположим, что вы хотите скрыть клавиатуру из EditText размещенного в DialogFragment ? Вы не можете использовать вышеописанный метод:

hideKeyboard(getActivity()); //won't work

Это не сработает, потому что вы передадите ссылку на хост- Activity Fragment , которая не будет иметь сфокусированного управления, пока отображается Fragment ! Вау! Поэтому, скрывая клавиатуру от фрагментов, я прибегаю к более низкому уровню, более обыченному и уродливому:

public static void hideKeyboardFrom(Context context, View view) {
    InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

Ниже приведена дополнительная информация, полученная из большего количества времени, потраченного впустую:

О windowSoftInputMode

Есть еще один спорный момент, о котором нужно знать. По умолчанию Android автоматически назначит начальный фокус первому EditText или настраиваемому элементу управления в вашей Activity . Из этого следует, что InputMethod (обычно мягкая клавиатура) будет реагировать на событие фокусировки, показывая себя. windowSoftInputMode в AndroidManifest.xml , когда установлен в stateAlwaysHidden , указывает клавиатуре игнорировать этот автоматически назначенный начальный фокус.

<activity
    android:name=".MyActivity"
    android:windowSoftInputMode="stateAlwaysHidden"/>

Практически невероятно, кажется, ничего не делает, чтобы клавиатура не открывалась, когда вы касаетесь focusable="false" управления (если контрольный элемент не назначен focusable="false" и / или focusableInTouchMode="false" ). По-видимому, параметр windowSoftInputMode применяется только к событиям автоматической фокусировки, а не к фокусу событий, вызванных событиями касания.

Поэтому stateAlwaysHidden ОЧЕНЬ плохо назван. Его следует, скорее всего, назвать ignoreInitialFocus .

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

UPDATE: больше способов получить токен окна

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

Это альтернативы для вышеуказанного кода if (view == null) view = new View(activity); Они не относятся прямо к вашей деятельности.

Внутри класса фрагмента:

view = getView().getRootView().getWindowToken();

Для фрагмента fragment в качестве параметра:

view = fragment.getView().getRootView().getWindowToken();

Начиная с вашего контента:

view = findViewById(android.R.id.content).getRootView().getWindowToken();

ОБНОВЛЕНИЕ 2: очистить фокус, чтобы снова не показывать клавиатуру, если вы открываете приложение из фона

Добавьте эту строку в конец метода:

view.clearFocus();

Question

В моем макете есть EditText и Button .

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




Пожалуйста, попробуйте этот ниже код в oncreate ()

EditText edtView = (EditText) findViewById (R.id.editTextConvertValue); edtView.setInputType (0);




This worked for me for all the bizarre keyboard behavior

private boolean isKeyboardVisible() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    mRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = mRootView.getRootView().getHeight() - (r.bottom - r.top);
    return heightDiff > 100; // if more than 100 pixels, its probably a keyboard...
}

protected void showKeyboard() {
    if (isKeyboardVisible())
        return;
    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    if (getCurrentFocus() == null) {
        inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
    } else {
        View view = getCurrentFocus();
        inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_FORCED);
    }
}

protected void hideKeyboard() {
    if (!isKeyboardVisible())
        return;
    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    View view = getCurrentFocus();
    if (view == null) {
        if (inputMethodManager.isAcceptingText())
            inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
    } else {
        if (view instanceof EditText)
            ((EditText) view).setText(((EditText) view).getText().toString()); // reset edit text bug on some keyboards bug
        inputMethodManager.hideSoftInputFromInputMethod(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}



Thanks to this SO answer , I derived the following which, in my case, works nicely when scrolling through the the fragments of a ViewPager...

private void hideKeyboard() {   
    // Check if no view has focus:
    View view = this.getCurrentFocus();
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

private void showKeyboard() {   
    // Check if no view has focus:
    View view = this.getCurrentFocus();
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
    }
}



For my case, I was using the a SearchView in the actionbar. After a user performs a search, the keyboard would pop open again.

Using the InputMethodManager did not close the keyboard. I had to clearFocus and set the focusable of the search view to false:

mSearchView.clearFocus();
mSearchView.setFocusable(false);



Короткий ответ

В вашем прослушивателе OnClick вызывается onEditorAction из EditText с IME_ACTION_DONE

button.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        someEditText.onEditorAction(EditorInfo.IME_ACTION_DONE)
    }
});

Развертывание

Я считаю, что этот метод лучше, проще и более согласован с шаблоном проектирования Android. В простом примере выше (и, как правило, в большинстве распространенных случаев) у вас будет EditText который имеет / имел фокус, и он также обычно вызывал клавиатуру в первую очередь (она, безусловно, может вызвать ее в многие распространенные сценарии). Таким же образом, он должен освободить клавиатуру, обычно это может быть сделано ImeAction . Просто посмотрите, как ведет себя EditText с android:imeOptions="actionDone" , вы хотите добиться того же поведения теми же средствами.

Проверьте этот ответ




У меня есть случай, где мой EditTextможет находиться и в a AlertDialog, поэтому клавиатура должна быть закрыта при увольнении. Следующий код, кажется, работает где угодно:

public static void hideKeyboard( Activity activity ) {
    InputMethodManager imm = (InputMethodManager)activity.getSystemService( Context.INPUT_METHOD_SERVICE );
    View f = activity.getCurrentFocus();
    if( null != f && null != f.getWindowToken() && EditText.class.isAssignableFrom( f.getClass() ) )
        imm.hideSoftInputFromWindow( f.getWindowToken(), 0 );
    else 
        activity.getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN );
}



В качестве альтернативы этому решению все вокруг , если вы хотите закрыть мягкую клавиатуру из любого места, не имея ссылки на поле (EditText), которое было использовано для открытия клавиатуры, но все же захотелось сделать это, если поле было сфокусировано, вы могли бы использовать это (из Activity):

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



Just use this optimized code in your activity:

if (this.getCurrentFocus() != null) {
    InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
    inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}



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

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

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




protected void hideSoftKeyboard(EditText input) {
    input.setInputType(0);
    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(input.getWindowToken(), 0);    
}



If you want to close the soft keyboard during a unit or functional test, you can do so by clicking the "back button" from your test:

// Close the soft keyboard from a Test
getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);

I put "back button" in quotes, since the above doesn't trigger the onBackPressed() for the Activity in question. It just closes the keyboard.

Make sure to pause for a little while before moving on, since it takes a little while to close the back button, so subsequent clicks to Views, etc., won't be registered until after a short pause (1 second is long enough ime).




Simple and Easy to use method, just call hideKeyboardFrom(YourActivity.this); to hide keyboard

/**
 * This method is used to hide keyboard
 * @param activity
 */
public static void hideKeyboardFrom(Activity activity) {
    InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}



У Saurabh Pareek есть лучший ответ.

Тем не менее, можно использовать правильные флаги.

/* hide keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

/* show keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

Пример реального использования

/* click button */
public void onClick(View view) {      
  /* hide keyboard */
  ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
      .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

  /* start loader to check parameters ... */
}

/* loader finished */
public void onLoadFinished(Loader<Object> loader, Object data) {
    /* parameters not valid ... */

    /* show keyboard */
    ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
        .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

    /* parameters valid ... */
}



Я использую пользовательскую клавиатуру для ввода шестнадцатеричного номера, поэтому я не могу открыть клавиатуру IMM ...

В v3.2.4_r1 setSoftInputShownOnFocus(boolean show) был добавлен для управления погодой или не отображать клавиатуру, когда TextView получает фокус, но ее все еще скрыто, поэтому необходимо использовать отражение:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
    try {
        Method method = TextView.class.getMethod("setSoftInputShownOnFocus", boolean.class);
        method.invoke(mEditText, false);
    } catch (Exception e) {
        // Fallback to the second method
    }
}

Для более старых версий я получил очень хорошие результаты (но далеко не идеальный) с помощью OnGlobalLayoutListener , добавленный с помощью ViewTreeObserver из моего корневого представления, а затем проверяя, показана ли клавиатура следующим образом:

@Override
public void onGlobalLayout() {
    Configuration config = getResources().getConfiguration();

    // Dont allow the default keyboard to show up
    if (config.keyboardHidden != Configuration.KEYBOARDHIDDEN_YES) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mRootView.getWindowToken(), 0);
    }
}

Это последнее решение может отображать клавиатуру в течение секунды секунды и беспорядок с помощью дескрипторов выделения.

Когда клавиатура входит в полноэкранный режим, onGlobalLayout не вызывается. Чтобы этого избежать, используйте TextView#setImeOptions(int) или в XML-декларации TextView:

android:imeOptions="actionNone|actionUnspecified|flagNoFullscreen|flagNoExtractUi"

Обновление: просто нашел, какие диалоги используют, чтобы никогда не показывать клавиатуру и работать во всех версиях:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
        WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);



Related