Como detecto se o teclado do software está visível no dispositivo Android ou não?


249

Existe uma maneira no Android de detectar se o teclado do software (também conhecido como "soft") está visível na tela?



1
o que pode ser uma solução para isso em certos casos (se um teclado de terceiros estiver instalado) é verificar as notificações globais, pois quando um teclado está aberto, há uma notificação do sistema que diz "alterar teclado" - pode ser feita com um NotificationListenerService
Prof

2
quase 8 anos e ainda solução não sólida, oh se introduzir um, que vai ser de API> 30 assim mesmo assim não importa ...
M.kazem Akhgary

Respostas:



276

Isso funciona para mim. Talvez essa seja sempre a melhor maneira para todas as versões .

Seria eficaz criar uma propriedade de visibilidade do teclado e observar essas alterações atrasadas porque o método onGlobalLayout chama muitas vezes. Também é bom verificar a rotação do dispositivo e windowSoftInputModenão é adjustNothing.

boolean isKeyboardShowing = false;
void onKeyboardVisibilityChanged(boolean opened) {
    print("keyboard " + opened);
}

// ContentView is the root view of the layout of this activity/fragment    
contentView.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {

        Rect r = new Rect();
        contentView.getWindowVisibleDisplayFrame(r);
        int screenHeight = contentView.getRootView().getHeight();

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        int keypadHeight = screenHeight - r.bottom;

        Log.d(TAG, "keypadHeight = " + keypadHeight);

        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            if (!isKeyboardShowing) {
                isKeyboardShowing = true
                onKeyboardVisibilityChanged(true)
            }
        }
        else {
            // keyboard is closed
            if (isKeyboardShowing) {
                isKeyboardShowing = false
                onKeyboardVisibilityChanged(false)
            }
        }
    }
});

3
Aqui está uma síntese
Faruk Toptas

1
Coloque isso em uma classe de utilitários e passe a atividade - agora útil em todo o aplicativo.
11747 Justin

2
E onde é contentViewdeclarado?
Code-Apprentice

1
@ Aprendiz de código Na atividade / fragmento que você deseja responder às alterações do teclado virtual. ContentView é a visualização raiz do layout dessa atividade / fragmento.
airowe

1
Trabalhou para mim no Android 6 e 7.
V.Market

71

tente isto:

InputMethodManager imm = (InputMethodManager) getActivity()
            .getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        writeToLog("Software Keyboard was shown");
    } else {
        writeToLog("Software Keyboard was not shown");
    }

9
Isso não funciona para mim. A ramificação mostrada no teclado é acionada mesmo quando o teclado nunca foi mostrado ou foi mostrado e depois fechado.
Peter Ajtai

30
sempre retorna verdadeiro.
shivang Trivedi

1
Sim, sempre retorna verdadeiro.
Léon Pelletier

Errado. Isso sempre retorna true
Gaurav Arora

178
É patético que a estrutura do Android esteja ausente e, pior ainda, inconsistente a esse respeito. Isso deveria ser super simples.
Vicky Chijwani

57

Criei uma classe simples que pode ser usada para isso: https://github.com/ravindu1024/android-keyboardlistener . Basta copiá-lo para o seu projeto e usar da seguinte maneira:

KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
{
    @Override
    public void onToggleSoftKeyboard(boolean isVisible)
    {
        Log.d("keyboard", "keyboard visible: "+isVisible);
    }
});

Onde no código exatamente eu tenho que colocar isso? Coloquei isso em uma atividade, no entanto, ele não detecta nenhuma aparência ou desaparecimento do teclado.
29516 toom

Bem, você pode colocá-lo em qualquer lugar dentro da sua atividade. Basta colocá-lo no método onCreate () após a chamada setContentView () e você deverá receber retornos de chamada. Btw, em que dispositivo você está experimentando?
Ravindu1024

@MaulikDodia eu verifiquei e funciona bem em fragmentos. Configure assim: KeyboardUtils.addKeyboardToggleListener (getActivity (), this); e deve funcionar. Em que dispositivo você está testando?
ravindu1024

Estou tentando no dispositivo Moto-G3. @ Ravindu1024
Maulik Dodia

Obrigado por este trecho, tenho uma pergunta que é esse código necessário para remover o ouvinte?
Pratik Butani 16/08/19

28

Muito fácil

1. Coloque o ID na sua visualização raiz

rootViewé apenas uma visualização apontando para minha visualização raiz, neste caso, a relative layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/addresses_confirm_root_view"
                android:background="@color/WHITE_CLR">

2. Inicialize sua visualização raiz em sua atividade:

RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view);

3. Detecte se o teclado está aberto ou fechado usando getViewTreeObserver()

    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();

                if (heightDiff > 100) { 
                    Log.e("MyActivity", "keyboard opened");
                } else { 
                    Log.e("MyActivity", "keyboard closed");
                }
            }
        });

15
Ei, companheiro, você poderia me dizer de onde vem essa mágica 100? Por que não 101 ou 99? Obrigado
Karoly

@ Karoly eu acho que isso pode ser e 1. Não importa. Somente este deve ser menor do que o comprimento real do teclado
Vlad

@Karoly basicamente, ele está comparando o tamanho da janela com o tamanho da visualização raiz da sua atividade. a aparência do teclado virtual não afeta o tamanho da janela principal. para que você ainda possa abaixar o valor de 100.
mr5 05/09

O número mágico depende do seu layout da barra superior, entre outras coisas. Portanto, é relativo ao seu aplicativo. Eu usei 400 em um dos meus.
Morten Holmgaard 8/08/19

lembre-se de que onGlobalLayout é chamado de todos os quadros; portanto, não faça coisas pesadas nele.
Akshay Gaonkar 13/09/19

8

Eu usei isso como base: http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android

/**
* To capture the result of IMM hide/show soft keyboard
*/
public class IMMResult extends ResultReceiver {
     public int result = -1;
     public IMMResult() {
         super(null);
}

@Override 
public void onReceiveResult(int r, Bundle data) {
    result = r;
}

// poll result value for up to 500 milliseconds
public int getResult() {
    try {
        int sleep = 0;
        while (result == -1 && sleep < 500) {
            Thread.sleep(100);
            sleep += 100;
        }
    } catch (InterruptedException e) {
        Log.e("IMMResult", e.getMessage());
    }
    return result;
}
}

Então escreveu este método:

public boolean isSoftKeyboardShown(InputMethodManager imm, View v) {

    IMMResult result = new IMMResult();
    int res;

    imm.showSoftInput(v, 0, result);

    // if keyboard doesn't change, handle the keypress
    res = result.getResult();
    if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN ||
            res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) {

        return true;
    }
    else
        return false;

}

Você pode usá-lo para testar todos os campos (EditText, AutoCompleteTextView, etc) que podem ter aberto uma tecla programável:

    InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    if(isSoftKeyboardShown(imm, editText1) | isSoftKeyboardShown(imm, autocompletetextview1))
        //close the softkeyboard
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

Obviamente, não é uma solução ideal, mas faz o trabalho.


2
Isso funciona. Se você implementar como singelton você pode aplicar a todos os edittexts na mudança de foco e ter um ouvinte teclado mundial
Rarw

@depperm getActivity () é específico para Fragments, tente YourActivityName.this. Veja também: stackoverflow.com/questions/14480129/…
Christopher Hackl


6

Você pode consultar esta resposta - https://stackoverflow.com/a/24105062/3629912

Funcionou para mim todas as vezes.

adb shell dumpsys window InputMethod | grep "mHasSurface"

Retornará true, se o teclado do software estiver visível.


10
Isso é útil apenas durante o desenvolvimento - não é uma solução para uso em um aplicativo. (Os usuários não terão adb em execução.)
ToolmakerSteve

5

Então, depois de muito tempo brincando com os Serviços de Acessibilidade, inserções de janelas, detecção de altura da tela etc., acho que encontrei uma maneira de fazer isso.

Isenção de responsabilidade: ele usa um método oculto no Android, o que significa que pode não ser consistente. No entanto, nos meus testes, parece funcionar.

O método é InputMethodManager # getInputMethodWindowVisibleHeight () e existe desde o Lollipop (5.0).

Chamada que retorna a altura, em pixels, do teclado atual. Em teoria, um teclado não deve ter 0 pixels de altura, então fiz uma verificação simples da altura (no Kotlin):

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
    //keyboard is shown
else {
    //keyboard is hidden
}

Uso a API oculta do Android para evitar a reflexão quando chamo métodos ocultos (faço muito isso para os aplicativos que desenvolvo, que são principalmente aplicativos de hacky / tuner), mas isso também deve ser possível com a reflexão:

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
val windowHeightMethod = InputMethodManager::class.java.getMethod("getInputMethodWindowVisibleHeight")
val height = windowHeightMethod.invoke(imm) as Int
//use the height val in your logic

Incrível uso de reflexões
kaustubhpatange

4

Isso foi muito menos complicado para os requisitos que eu precisava. Espero que isso possa ajudar:

Em MainActivity:

public void dismissKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
    mKeyboardStatus = false;
}

public void showKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    mKeyboardStatus = true;
}

private boolean isKeyboardActive(){
    return mKeyboardStatus;
}

O valor booleano primitivo padrão para mKeyboardStatus será inicializado como false .

Em seguida, verifique o valor da seguinte maneira e execute uma ação, se necessário:

 mSearchBox.requestFocus();
    if(!isKeyboardActive()){
        showKeyboard();
    }else{
        dismissKeyboard();
    }

4

Isso deve funcionar se você precisar verificar o status do teclado:

fun Activity.isKeyboardOpened(): Boolean {
    val r = Rect()

    val activityRoot = getActivityRoot()
    val visibleThreshold = dip(UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP)

    activityRoot.getWindowVisibleDisplayFrame(r)

    val heightDiff = activityRoot.rootView.height - r.height()

    return heightDiff > visibleThreshold;
}

fun Activity.getActivityRoot(): View {
    return (findViewById<ViewGroup>(android.R.id.content)).getChildAt(0);
}

Onde UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP= 100 e dip () é uma função anko que converte dpToPx:

fun dip(value: Int): Int {
    return (value * Resources.getSystem().displayMetrics.density).toInt()
}

3

Fiz isso definindo um GlobalLayoutListener, da seguinte maneira:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightView = activityRootView.getHeight();
                int widthView = activityRootView.getWidth();
                if (1.0 * widthView / heightView > 3) {
                    //Make changes for Keyboard not visible
                } else {
                    //Make changes for keyboard visible
                }
            }
        });

Isso será chamado MUITO frequentemente
Denis Kniazhev

Em que casos isso será diferente da resposta @BrownsooHan? Estou procurando uma maneira que um aplicativo que desenha sobre outros aplicativos para ficar fora do caminho do teclado está sendo exibido.
Evan Langlois

Sua resposta é fundamentalmente a mesma que a minha, só que eu fiz a minha muitos meses antes da dele, e ele tem mais votos positivos.
precisa saber é o seguinte

3

Experimente este código que está realmente funcionando se KeyboardShown for Shown, então essa função retornará valor verdadeiro ....

private final String TAG = "TextEditor";
private TextView mTextEditor;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_editor);
    mTextEditor = (TextView) findViewById(R.id.text_editor);
    mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            isKeyboardShown(mTextEditor.getRootView());
        }
    });
}

private boolean isKeyboardShown(View rootView) {
    /* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
    final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;

    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    /* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
    int heightDiff = rootView.getBottom() - r.bottom;
    /* Threshold size: dp to pixels, multiply with display density */
    boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;

    Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
            + "root view height:" + rootView.getHeight() + ", rect:" + r);

    return isKeyboardShown;
}

O isKeyboardShown continua se chamando quando não é mostrado.
Mandeep Singh

2

No meu caso, eu tinha apenas um EditTextpara gerenciar no meu layout, então vim com esta solução. Funciona bem, basicamente é um costume EditTextque escuta o foco e envia uma transmissão local se o foco mudar ou se o botão Voltar / Concluído for pressionado. Para trabalhar, você precisa colocar um manequim Viewno layout com android:focusable="true"e android:focusableInTouchMode="true"porque, quando você ligar, clearFocus()o foco será reatribuído para a primeira visualização focalizável. Exemplo de visualização fictícia:

<View
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"/>

Informações adicionais

A solução que detecta a diferença nas alterações de layout não funciona muito bem porque depende muito da densidade da tela, pois 100px pode ser muito em um determinado dispositivo e nada em outros pode gerar falso-positivos. Também diferentes fornecedores têm teclados diferentes.


1

No Android, você pode detectar através do shell do ADB. Eu escrevi e usei este método:

{
        JSch jsch = new JSch();
        try {
            Session session = jsch.getSession("<userName>", "<IP>", 22);
            session.setPassword("<Password>");
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();

            ChannelExec channel = (ChannelExec)session.openChannel("exec");
            BufferedReader in = new BufferedReader(new    
            InputStreamReader(channel.getInputStream()));
            channel.setCommand("C:/Android/android-sdk/platform-tools/adb shell dumpsys window 
            InputMethod | findstr \"mHasSurface\"");
            channel.connect();

            String msg = null;
            String msg2 = " mHasSurface=true";

            while ((msg = in.readLine()) != null) {
                Boolean isContain = msg.contains(msg2);
                log.info(isContain);
                if (isContain){
                    log.info("Hiding keyboard...");
                    driver.hideKeyboard();
                }
                else {
                    log.info("No need to hide keyboard.");
                }
            }

            channel.disconnect();
            session.disconnect();

        } catch (JSchException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

1
Você pode melhorar esta resposta com um exemplo mais concreto, com todas as importações e um exemplo de trabalho?
usar o seguinte

1
final View activityRootView = findViewById(R.id.rootlayout);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            Rect r = new Rect();
            activityRootView.getWindowVisibleDisplayFrame(r);

            int screenHeight = activityRootView.getRootView().getHeight();
            Log.e("screenHeight", String.valueOf(screenHeight));
            int heightDiff = screenHeight - (r.bottom - r.top);
            Log.e("heightDiff", String.valueOf(heightDiff));
            boolean visible = heightDiff > screenHeight / 3;
            Log.e("visible", String.valueOf(visible));
            if (visible) {
                Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show();
            }
        }
});

1

A resposta de @iWantScala é ótima, mas não funcionar para mim
rootView.getRootView().getHeight()sempre tem o mesmo valor

Uma maneira é definir dois Vars

private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;

adicionar ouvinte global

rootView.getViewTreeObserver()
    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            currentRootViewHeight = rootView.getHeight();
            if (currentRootViewHeight > maxRootViewHeight) {
                maxRootViewHeight = currentRootViewHeight;
            }
        }
    });

então verifique

if (currentRootViewHeight >= maxRootViewHeight) {
    // Keyboard is hidden
} else {
    // Keyboard is shown
}

funciona bem


1

Finalmente, existe uma maneira direta a partir do Android R, com base no Kotlin agora.

 val imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
     //Ime is visible
     //Lets move our view by the height of the IME
     view.translationX = imeInsets.bottom }

0

Eu tive um problema parecido. Eu precisava reagir ao botão Enter na tela (que escondia o teclado). Nesse caso, você pode assinar a OnEditorAction da exibição de texto com a qual o teclado foi aberto - se você tiver várias caixas editáveis, inscreva-se em todas elas.

Na sua Atividade, você tem controle total do teclado; portanto, em nenhum momento você enfrentará o problema de o teclado ser aberto ou não, se você ouvir todos os eventos de abertura e fechamento.


Não funciona para mim. Eu recebo apenas a tecla Enter no OnEditorAction.
3c71 6/12/12

0

Existe um método direto para descobrir isso. E, não requer as alterações de layout.
Por isso, também funciona no modo imersivo em tela cheia.
Infelizmente, porém, não funciona em todos os dispositivos. Então você precisa testá-lo com seu (s) dispositivo (s).

O truque é tentar ocultar ou mostrar o teclado virtual e capturar o resultado dessa tentativa.
Se funcionar corretamente, o teclado não será realmente mostrado ou oculto. Nós apenas pedimos o estado.

Para manter-se atualizado, basta repetir esta operação, por exemplo, a cada 200 milissegundos, usando um manipulador.

A implementação abaixo faz apenas uma única verificação.
Se você fizer várias verificações, habilite todos os testes (_keyboardVisible).

public interface OnKeyboardShowHide
{
    void    onShowKeyboard( Object param );
    void    onHideKeyboard( Object param );
}

private static Handler      _keyboardHandler    = new Handler();
private boolean             _keyboardVisible    = false;
private OnKeyboardShowHide  _keyboardCallback;
private Object              _keyboardCallbackParam;

public void start( OnKeyboardShowHide callback, Object callbackParam )
{
    _keyboardCallback      = callback;
    _keyboardCallbackParam = callbackParam;
    //
    View view = getCurrentFocus();
    if (view != null)
    {
        InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
        imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
        imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
    }
    else // if (_keyboardVisible)
    {
        _keyboardVisible = false;
        _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
    }
}

private ResultReceiver      _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
{
    @Override
    protected void onReceiveResult( int resultCode, Bundle resultData )
    {
        switch (resultCode)
        {
            case InputMethodManager.RESULT_SHOWN :
            case InputMethodManager.RESULT_UNCHANGED_SHOWN :
                // if (!_keyboardVisible)
                {
                    _keyboardVisible = true;
                    _keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
                }
                break;
            case InputMethodManager.RESULT_HIDDEN :
            case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
                // if (_keyboardVisible)
                {
                    _keyboardVisible = false;
                    _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
                }
                break;
        }
    }
};

como chamá-lo e onde?
Mahdi Astanei

0

Aqui está uma solução alternativa para saber se o teclado programável está visível.

  1. Verifique se há serviços em execução no sistema usando ActivityManager.getRunningServices (max_count_of_services);
  2. Nas instâncias ActivityManager.RunningServiceInfo retornadas, verifique clientCount valor de para obter o serviço de teclado .
  3. O clientCount mencionado acima será incrementado sempre que o teclado virtual for exibido. Por exemplo, se clientCount fosse inicialmente 1, seria 2 quando o teclado for mostrado.
  4. Na dispensa do teclado, o clientCount é decrementado. Nesse caso, ele é redefinido para 1.

Alguns dos teclados populares têm determinadas palavras-chave em suas classes

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = KeyboardService
  4. Fleksy = teclado
  5. Adaptxt = IME (KPTAdaptxtIME)
  6. Inteligente = teclado (teclado inteligente)

No ActivityManager.RunningServiceInfo, verifique os padrões acima em ClassNames. Além disso, o clientPackage = android do ActivityManager.RunningServiceInfo , indicando que o teclado está vinculado ao sistema.

As informações acima mencionadas podem ser combinadas para uma maneira estrita de descobrir se o teclado virtual está visível.


0

Como você deve saber, o teclado do software Android ficará visível apenas quando houver um possível evento de digitação. Em outras palavras, o teclado fica visível apenas quando o EditText está focado. isso significa que você pode ficar sabendo que o teclado está visível ou não usando o OnFocusChangeListener .

//Declare this Globally

public boolean isKeyBoardVisible = false;

//In OnCreate *[For Activity]*, OnCreateView *[For Fragment]*

text_send.setOnFocusChangeListener(new View.OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus)
            isKeyBoardVisible = true;
        else
            isKeyBoardVisible = false;
    }
});

Agora você pode usar isKeyBoardVisible variável em qualquer lugar da classe para se o teclado está Aberto ou Não. Isso funcionou bem para mim.

Nota: Esse processo não funciona quando o teclado é aberto programaticamente usando InputMethodManager, porque isso não chama OnFocusChangeListener.


não é realmente um truque, não funcionou em um caso de fragmento aninhado. Não posso dizer sobre atividades como eu não tentei isso ainda.
antroid 3/06/19

0

Eu converti a resposta para o kotlin, espero que isso ajude os usuários do kotlin.

private fun checkKeyboardVisibility() {
    var isKeyboardShowing = false

    binding.coordinator.viewTreeObserver.addOnGlobalLayoutListener {
        val r = Rect()
        binding.coordinator.getWindowVisibleDisplayFrame(r)
        val screenHeight = binding.coordinator.rootView.height

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        val keypadHeight = screenHeight - r.bottom


        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            if (!isKeyboardShowing) {
                isKeyboardShowing = true

            }
        } else {
            // keyboard is closed
            if (isKeyboardShowing) {
                isKeyboardShowing = false

            }
        }
    }
}

0

Ele funciona com o sinalizador AdjustNothing de eventos de atividade e ciclo de vida. Também com Kotlin:

/**
 * This class uses a PopupWindow to calculate the window height when the floating keyboard is opened and closed
 *
 * @param activity The parent activity
 *  The root activity that uses this KeyboardManager
 */
class KeyboardManager(private val activity: AppCompatActivity) : PopupWindow(activity), LifecycleObserver {

    private var observerList = mutableListOf<((keyboardTop: Int) -> Unit)>()

    /** The last value of keyboardTop */
    private var keyboardTop: Int = 0

    /** The view that is used to calculate the keyboard top  */
    private val popupView: View?

    /** The parent view  */
    private var parentView: View

    var isKeyboardShown = false
        private set

    /**
     * Create transparent view which will be stretched over to the full screen
     */
    private fun createFullScreenView(): View {
        val view = LinearLayout(activity)
        view.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT)
        view.background = ColorDrawable(Color.TRANSPARENT)
        return view
    }

    init {
        this.popupView = createFullScreenView()
        contentView = popupView

        softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE or LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
        inputMethodMode = INPUT_METHOD_NEEDED

        parentView = activity.findViewById(android.R.id.content)

        width = 0
        height = LayoutParams.MATCH_PARENT

        popupView.viewTreeObserver.addOnGlobalLayoutListener {
            val rect = Rect()
            popupView.getWindowVisibleDisplayFrame(rect)

            val keyboardTop = rect.bottom
            if (this.keyboardTop != keyboardTop) {
                isKeyboardShown = keyboardTop < this.keyboardTop
                this.keyboardTop = keyboardTop
                observerList.forEach { it(keyboardTop) }
            }
        }
        activity.lifecycle.addObserver(this)
    }

    /**
     * This must be called after the onResume of the Activity or inside view.post { } .
     * PopupWindows are not allowed to be registered before the onResume has finished
     * of the Activity
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun start() {
        parentView.post {
            if (!isShowing && parentView.windowToken != null) {
                setBackgroundDrawable(ColorDrawable(0))
                showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
            }
        }
    }

    /**
     * This manager will not be used anymore
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun close() {
        activity.lifecycle.removeObserver(this)
        observerList.clear()
        dismiss()
    }

    /**
     * Set the keyboard top observer. The observer will be notified when the keyboard top has changed.
     * For example when the keyboard is opened or closed
     *
     * @param observer The observer to be added to this provider
     */
    fun registerKeyboardTopObserver(observer: (keyboardTop: Int) -> Unit) {
        observerList.add(observer)
    }
}

Método útil para manter a visualização sempre acima do teclado

fun KeyboardManager.updateBottomMarginIfKeyboardShown(
        view: View,
        activity: AppCompatActivity,
        // marginBottom of view when keyboard is hide
        marginBottomHideKeyboard: Int,
        // marginBottom of view when keybouard is shown
        marginBottomShowKeyboard: Int
) {
    registerKeyboardTopObserver { bottomKeyboard ->
        val bottomView = ViewUtils.getFullViewBounds(view).bottom
        val maxHeight = ScreenUtils.getFullScreenSize(activity.windowManager).y
        // Check that view is within the window size
        if (bottomView < maxHeight) {
            if (bottomKeyboard < bottomView) {
                ViewUtils.updateMargin(view, bottomMargin = bottomView - bottomKeyboard +
                        view.marginBottom + marginBottomShowKeyboard)
            } else ViewUtils.updateMargin(view, bottomMargin = marginBottomHideKeyboard)
        }
    }
}

Onde getFullViewBounds

fun getLocationOnScreen(view: View): Point {
    val location = IntArray(2)
    view.getLocationOnScreen(location)
    return Point(location[0], location[1])
}

fun getFullViewBounds(view: View): Rect {
     val location = getLocationOnScreen(view)
     return Rect(location.x, location.y, location.x + view.width,
            location.y + view.height)
 }

Onde getFullScreenSize

fun getFullScreenSize(wm: WindowManager? = null) =
            getScreenSize(wm) { getRealSize(it) }

private fun getScreenSize(wm: WindowManager? = null, block: Display.(Point) -> Unit): Point {
    val windowManager = wm ?: App.INSTANCE.getSystemService(Context.WINDOW_SERVICE)
            as WindowManager
    val point = Point()
    windowManager.defaultDisplay.block(point)
    return point
}

Onde updateMargin

fun updateMargin(
        view: View,
        leftMargin: Int? = null,
        topMargin: Int? = null,
        rightMargin: Int? = null,
        bottomMargin: Int? = null
) {
    val layoutParams = view.layoutParams as ViewGroup.MarginLayoutParams
    if (leftMargin != null) layoutParams.leftMargin = leftMargin
    if (topMargin != null) layoutParams.topMargin = topMargin
    if (rightMargin != null) layoutParams.rightMargin = rightMargin
    if (bottomMargin != null) layoutParams.bottomMargin = bottomMargin
    view.layoutParams = layoutParams
}

-1

Fiz isso da seguinte maneira, mas é relevante apenas se o seu objetivo é fechar / abrir o keyboad.

close example: (verificando se o teclado já está fechado, se não - fechando)

imm.showSoftInput(etSearch, InputMethodManager.HIDE_IMPLICIT_ONLY, new ResultReceiver(null) {
                    @Override
                    protected void onReceiveResult(int resultCode, Bundle resultData) {
                        super.onReceiveResult(resultCode, resultData);
                        if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN)
                            imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    }
                });

A questão foi relacionado para descobrir qualquer teclado está mostrando ou não
Gopal Singh Sirvi

-1

a pode estar usando:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    Log.d(
    getClass().getSimpleName(), 
    String.format("conf: %s", newConfig));

    if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
        onHardwareKeyboardChange(newConfig.hardKeyboardHidden);

        hardKeyboardHidden = newConfig.hardKeyboardHidden;
    }

    if (newConfig.keyboardHidden != keyboardHidden) {
        onKeyboardChange(newConfig.keyboardHidden);

        keyboardHidden = newConfig.hardKeyboardHidden;
    }

}

public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;

//todo
private void onKeyboardChange(int keyboardHidden) {

}

//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {

}

Isso só vai trabalho para teclado de hardware, e não ele software um
anthonymonori


-1

Se você suporta apis para AndroidR no seu aplicativo, pode usar o método abaixo.

In kotlin :
    var imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
        view.translationX = imeInsets.bottom 
    }

Nota: Isso está disponível apenas para o AndroidR e, abaixo, a versão do Android precisa seguir algumas das outras respostas, ou eu atualizarei para isso.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.