Кнопка перехвата назад с мягкой клавиатуры


у меня есть активность с несколькими полями ввода. При запуске активности отображается программная клавиатура. Когда кнопка "Назад" нажата, мягкая клавиатура закрывается, и чтобы закрыть активность, мне нужно еще раз нажать кнопку "Назад".

Итак, вопрос: Можно ли перехватить кнопку "назад", чтобы закрыть мягкую клавиатуру и закончить работу одним нажатием кнопки "назад" без создания пользовательского InputMethodService?

P. S. Я знаю как перехватить кнопку обратно в других случаях: onKeyDown() или onBackPressed() но это не работает в этом случае: перехватывается только второе нажатие кнопки "Назад".

8 74

8 ответов:

да, вполне возможно показать и спрятать клавиатуру и перехватить звоноки к задней кнопке. Это немного дополнительные усилия, как уже упоминалось, нет прямого способа сделать это в API. Ключ должен переопределить boolean dispatchKeyEventPreIme(KeyEvent) в макете. То, что мы делаем, это создать наш макет. Я выбрал RelativeLayout, так как это было основой моей деятельности.

<?xml version="1.0" encoding="utf-8"?>
<com.michaelhradek.superapp.utilities.SearchLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.michaelhradek.superapp"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/white">

внутри нашей деятельности мы настраиваем наши поля ввода и вызываем setActivity(...) функция.

private void initInputField() {
    mInputField = (EditText) findViewById(R.id.searchInput);        

    InputMethodManager imm = 
        (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 
            InputMethodManager.HIDE_IMPLICIT_ONLY);

    mInputField.setOnEditorActionListener(new OnEditorActionListener() {

        @Override
        public boolean onEditorAction(TextView v, int actionId,
                KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                performSearch();
                return true;
            }

            return false;
        }
    });

    // Let the layout know we are going to be overriding the back button
    SearchLayout.setSearchActivity(this);
}

очевидно, что initInputField() функция устанавливает поле ввода. Он также позволяет ввести ключ для выполнения функции (в моем случае поиск).

@Override
public void onBackPressed() {
    // It's expensive, if running turn it off.
    DataHelper.cancelSearch();
    hideKeyboard();
    super.onBackPressed();
}

когда onBackPressed() называется в нашем макете мы тогда можем делать все, что мы хотим, как скрыть клавиатуру:

private void hideKeyboard() {
    InputMethodManager imm = (InputMethodManager) 
        getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(mInputField.getWindowToken(), 0);
}

в любом случае, вот мое переопределение RelativeLayout.

package com.michaelhradek.superapp.utilities;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.RelativeLayout;

/**
 * The root element in the search bar layout. This is a custom view just to 
 * override the handling of the back button.
 * 
 */
public class SearchLayout extends RelativeLayout {

    private static final String TAG = "SearchLayout";

    private static Activity mSearchActivity;;

    public SearchLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SearchLayout(Context context) {
        super(context);
    }

    public static void setSearchActivity(Activity searchActivity) {
        mSearchActivity = searchActivity;
    }

    /**
     * Overrides the handling of the back key to move back to the 
     * previous sources or dismiss the search dialog, instead of 
     * dismissing the input method.
     */
    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {
        Log.d(TAG, "dispatchKeyEventPreIme(" + event + ")");
        if (mSearchActivity != null && 
                    event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            KeyEvent.DispatcherState state = getKeyDispatcherState();
            if (state != null) {
                if (event.getAction() == KeyEvent.ACTION_DOWN
                        && event.getRepeatCount() == 0) {
                    state.startTracking(event, this);
                    return true;
                } else if (event.getAction() == KeyEvent.ACTION_UP
                        && !event.isCanceled() && state.isTracking(event)) {
                    mSearchActivity.onBackPressed();
                    return true;
                }
            }
        }

        return super.dispatchKeyEventPreIme(event);
    }
}

к сожалению, я не могу взять на себя всю ответственность. Если вы проверите Android источник для быстрого SearchDialog box вы увидите, откуда пришла идея.

onKeyDown () и onBackPressed() не работает в этом случае. Вы должны использовать onKeyPreIme.

первоначально, вы должны создать пользовательский текст редактирования, который расширяет EditText. И тогда вы должны реализовать onKeyPreIme метод, который управляет KeyEvent.KEYCODE_BACK. После этого достаточно одного нажатия назад, чтобы решить вашу проблему. Это решение работает для меня отлично.

CustomEditText.java

public class CustomEditText extends EditText {

    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            // User has pressed Back key. So hide the keyboard
            InputMethodManager mgr = (InputMethodManager)         

           getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            mgr.hideSoftInputFromWindow(this.getWindowToken(), 0);
            // TODO: Hide your view as you do it in your activity
        }
        return false;
}

в XML

<com.YOURAPP.CustomEditText
     android:id="@+id/CEditText"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"/> 

в работе

public class MainActivity extends Activity {
   private CustomEditText editText;

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      editText = (CustomEditText) findViewById(R.id.CEditText);
   }
}

я узнал, что переопределение dispatchKeyEventPreIme метод класса Layout также работает хорошо. Просто установите свой основной вид деятельности в качестве атрибута и запустите предопределенный метод.

public class LinearLayoutGradient extends LinearLayout {
    MainActivity a;

    public void setMainActivity(MainActivity a) {
        this.a = a;
    }

    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {
        if (a != null) {
            InputMethodManager imm = (InputMethodManager) a
                .getSystemService(Context.INPUT_METHOD_SERVICE);

            if (imm.isActive() && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                a.launchMethod;
            }
        }

        return super.dispatchKeyEventPreIme(event);
    }
}

Я имел успех, переопределив dispatchKeyEvent:

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        finish();
        return true;
    }
    return super.dispatchKeyEvent(event);
}

он скрывает клавиатуру и завершает работу.

как вы показываете мягкую клавиатуру?

если вы используете InputMethodManager.showSoftInput(), вы можете попробовать пройти в ResultReceiver и осуществляет onReceiveResult() обработки RESULT_HIDDEN

http://developer.android.com/reference/android/view/inputmethod/InputMethodManager.html

У меня была та же проблема, но я обошел ее, перехватывая нажатие клавиши Назад. В моем случае (HTC Desire, Android 2.2, Application API Level 4) он закрывает клавиатуру и сразу же заканчивает работу. Не знаю, почему это не должно работать для вас:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        onBackPressed();
        return true;
    }
    return super.onKeyUp(keyCode, event);
}

/**
 * Called when the activity has detected the user's press of the back key
 */
private void onBackPressed() {
    Log.e(TAG, "back pressed");
    finish();
}

использовать onKeyPreIme(int keyCode, KeyEvent event) метод и проверка на KeyEvent.KEYCODE_BACK событие. Это очень просто, не делая каких-либо фантазии кодирования.

попробуйте этот код в вашей обратной реализации ( кнопка блокировки назад в android):

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

Я предлагаю вам посмотреть @ закрыть / скрыть программную клавиатуру Android