web-dev-qa-db-fra.com

Android: Détecter le clavier logiciel ouvert

Lorsque le clavier logiciel s'ouvre, je souhaite que la vue de défilement défile vers le bas.

Pour cela, je peux utiliser: fullScroll (View.FOCUS_DOWN);

Mais comment puis-je déclencher cette commande après le déclenchement de l'événement d'ouverture du clavier logiciel?

25
Noah Seidman

Per ce post et ce post sur les développeurs Android, il ne semble pas qu'il soit possible de faire ce que vous voulez. Vous voudrez peut-être réexaminer votre cas d'utilisation pour ce que vous faites. Peut-être que l'un des softInputMode flags fonctionnera pour vous.

22
Rich Schuler

Voici ma solution:

1/Une interface simple

public interface KeyboardVisibilityListener {
    void onKeyboardVisibilityChanged(boolean keyboardVisible);
}

2/Une méthode d’utilité (placez-la où vous voulez, par exemple dans une classe nommée KeyboardUtil)

public static void setKeyboardVisibilityListener(Activity activity, KeyboardVisibilityListener keyboardVisibilityListener) {
    View contentView = activity.findViewById(Android.R.id.content);
    contentView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        private int mPreviousHeight;

        @Override
        public void onGlobalLayout() {
            int newHeight = contentView.getHeight();
            if (mPreviousHeight != 0) {
                if (mPreviousHeight > newHeight) {
                    // Height decreased: keyboard was shown
                    keyboardVisibilityListener.onKeyboardVisibilityChanged(true);
                } else if (mPreviousHeight < newHeight) {
                    // Height increased: keyboard was hidden
                    keyboardVisibilityListener.onKeyboardVisibilityChanged(false);
                } else {
                    // No change
                }
            }
            mPreviousHeight = newHeight;
        }
    });
}

3/Utilisez une activité de cette façon (un bon endroit est dans onCreate):

KeyboardUtil.setKeyboardVisibilityListener(this, mKeyboardVisibilityListener);
39
BoD

regarder la date, peut-être avez-vous une solution à votre question, sinon:

Voici la même réponse que j'ai faite à une autre question liée: Y at-il un moyen de dire si le clavier logiciel est affiché?

mais je copie la réponse complète ici pour éviter les liens morts:

Veuillez vérifier modifications de configuration pour votre activité.

Ceci pour votre AndroidManifest.xml 

et ceci pour votre Activité classe http://developer.Android.com/reference/Android/app/Activity.html#onConfigurationChanged(Android.content.res.Configuration)

Vous devez @Override la méthode publique onConfigurationChanged (Android.content.res.Configuration) de votre activité pour pouvoir gérer, par exemple, les valeurs suivantes:
hardKeyboardHidden,
clavier,
keyboardHidden 

Pour toutes les valeurs possibles, vérifiez http://developer.Android.com/reference/Android/content/res/Configuration.html

Vous verrez quelque chose comme ça:

HARDKEYBOARDHIDDEN_NO   
HARDKEYBOARDHIDDEN_UNDEFINED    
HARDKEYBOARDHIDDEN_YES  
KEYBOARDHIDDEN_NO   
KEYBOARDHIDDEN_UNDEFINED    
KEYBOARDHIDDEN_YES  
KEYBOARD_12KEY  
KEYBOARD_NOKEYS 
KEYBOARD_QWERTY 
KEYBOARD_UNDEFINED

Vous pourrez également lire quelque chose comme ceci:

public int  hardKeyboardHidden  A flag indicating whether the hard keyboard has been      hidden.
public int  keyboard    The kind of keyboard attached to the device.
public int  keyboardHidden  A flag indicating whether any keyboard is available.

METTRE À JOUR:

Voici un échantillon spécifique de ce dont je parle:

http://developer.Android.com/guide/topics/resources/runtime-changes.html

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

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
    // Checks whether a hardware keyboard is available
    if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
        Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
    } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
        Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
    }
}

J'espère que cela vous aide

7
yeradis

La seule façon pour moi de contourner ce problème consiste à configurer Android de mon activité: windowSoftInputMode = "adjustResize" puis à intégrer une "vue de détecteur" personnalisée dans la présentation pour gérer un changement de taille Listener) pour activer/désactiver le clavier logiciel.

Le post suivant décrit une approche pour l'implémenter: EditText ne déclenche pas de changement lorsque l'utilisateur clique en arrière

2
Roberto Andrade

Ça marche pour moi

parent.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {

            boolean someHasFocus = false;

            if(Host.hasFocus())
                someHasFocus = true;
            if(folder.hasFocus())
                someHasFocus = true;
            if(user.hasFocus())
                someHasFocus = true;
            if(pass.hasFocus())
                someHasFocus = true;

            if(someHasFocus){
                if(bottom>oldBottom){
                    // Keyboard Close
                    viewToHide.setVisibility(View.VISIBLE);

                }else if(bottom<oldBottom){
                   // Keyboard Open
                    viewToHide.setVisibility(View.GONE);
                }

            }else{
                // show
                viewToHide.setVisibility(View.VISIBLE);
            }
        }
    });

Où parent est la disposition principale, viewToHide est la vue qui s'affiche ou se cache lorsque le clavier est affiché, et que l'hôte, le dossier, l'utilisateur et le mot de passe sont le texte d'édition de mon formulaire.

Et ceci dans le manifeste

Android:windowSoftInputMode="stateHidden|adjustResize"

J'espère que cette aide

1
Ramón Pérez Silva

Voici ma solution. Il n'a pas besoin d'Android: windowSoftInputMode = "adjustResize"

public abstract class KeyboardActivity extends Activity {
    public static final int MIN_KEYBOARD_SIZE = 100;
    private Window mRootWindow;
    private View mRootView;
    private int mKeyboardHeight = -1;
    private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {

    public int height;
    public void onGlobalLayout() {
            Rect r = new Rect();
        View view = mRootWindow.getDecorView();
        view.getWindowVisibleDisplayFrame(r);
        if (height != r.height()) {
            int diff = height - r.height();
            height = r.height();
            if (Math.abs(diff) > MIN_KEYBOARD_SIZE) {
                int diff = height - r.height();
                if (height != 0 && Math.abs(diff) > MIN_KEYBOARD_SIZE) {
                    mKeyboardHeight = Math.abs(diff);
                    if (diff > 0) {
                        onKeyboardOpen();
                    } else {
                        onKeyboardClosed();
                    }
                }
                height = r.height();
            }
        }
    };

    protected abstract void onKeyboardClosed();

    protected abstract void onKeyboardOpen();

    /**
     * Should return keyboard height, if keyboard was shown at least once;
     * @return keyboard height or -1
     */
    protected int getKeyboardHeight() {
        return mKeyboardHeight;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mRootWindow = getWindow();
        mRootView = mRootWindow.getDecorView().findViewById(Android.R.id.content);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mRootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
    }

    @Override
    protected void onStop() {
        super.onStop();
        mRootView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
    }
}

Ensuite, j'ai simplement étendu mon activité à partir de cette activité et remplacé les méthodes onKeyboardClosed/onKeyboardOpen. 

1
Grimmy

La réponse de @ BoD fonctionne bien si je supprime la ligne suivante.

if (mPreviousHeight != 0) {
     /* other code is same, because
        mPreviousHeight is 0 when it comes first */
}
0
venkat

pour ce que je faisais pareil:

  import Java.util.ArrayList;
import Java.util.List;
import Java.util.concurrent.atomic.AtomicBoolean;

import Android.os.Handler;
import Android.os.Message;
import Android.view.View;
import Android.view.ViewGroup;
import Android.view.inputmethod.InputMethodManager;
import Android.widget.EditText;

public class SoftKeyboard implements View.OnFocusChangeListener
{
    private static final int CLEAR_FOCUS = 0;

    private ViewGroup layout;
    private int layoutBottom;
    private InputMethodManager im;
    private int[] coords;
    private boolean isKeyboardShow;
    private SoftKeyboardChangesThread softKeyboardThread;
    private List<EditText> editTextList;

    private View tempView; // reference to a focused EditText

    public SoftKeyboard(ViewGroup layout, InputMethodManager im)
    {
        this.layout = layout;
        keyboardHideByDefault();
        initEditTexts(layout);
        this.im = im;
        this.coords = new int[2];
        this.isKeyboardShow = false;
        this.softKeyboardThread = new SoftKeyboardChangesThread();
        this.softKeyboardThread.start();
    }


    public void openSoftKeyboard()
    {
        if(!isKeyboardShow)
        {
            layoutBottom = getLayoutCoordinates();
            im.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);
            softKeyboardThread.keyboardOpened();
            isKeyboardShow = true;
        }
    }

    public void closeSoftKeyboard()
    {
        if(isKeyboardShow)
        {
            im.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
            isKeyboardShow = false;
        }
    }

    public void setSoftKeyboardCallback(SoftKeyboardChanged mCallback)
    {
        softKeyboardThread.setCallback(mCallback);
    }

    public void unRegisterSoftKeyboardCallback()
    {
        softKeyboardThread.stopThread();
    }

    public interface SoftKeyboardChanged
    {
        public void onSoftKeyboardHide();
        public void onSoftKeyboardShow();
    }

    private int getLayoutCoordinates()
    {
        layout.getLocationOnScreen(coords);
        return coords[1] + layout.getHeight();
    }

    private void keyboardHideByDefault()
    {
        layout.setFocusable(true);
        layout.setFocusableInTouchMode(true);
    }

    /*
     * InitEditTexts now handles EditTexts in nested views
     * Thanks to Francesco Verheye ([email protected])
     */
    private void initEditTexts(ViewGroup viewgroup)
    {
        if(editTextList == null)
            editTextList = new ArrayList<EditText>();

        int childCount = viewgroup.getChildCount();
        for(int i=0; i<= childCount-1;i++)
        {
            View v = viewgroup.getChildAt(i);

            if(v instanceof ViewGroup)
            {
                initEditTexts((ViewGroup) v);
            }

            if(v instanceof EditText)
            {
                EditText editText = (EditText) v;
                editText.setOnFocusChangeListener(this);
                editText.setCursorVisible(true);
                editTextList.add(editText);
            }
        }
    }

    /*
     * OnFocusChange does update tempView correctly now when keyboard is still shown
     * Thanks to Israel Dominguez ([email protected])
     */
    @Override
    public void onFocusChange(View v, boolean hasFocus)
    {
        if(hasFocus)
        {
            tempView = v;
            if(!isKeyboardShow)
            {
                layoutBottom = getLayoutCoordinates();
                softKeyboardThread.keyboardOpened();
                isKeyboardShow = true;
            }
        }
    }

    // This handler will clear focus of selected EditText
    private final Handler mHandler = new Handler()
    {
        @Override
        public void handleMessage(Message m)
        {
            switch(m.what)
            {
                case CLEAR_FOCUS:
                    if(tempView != null)
                    {
                        tempView.clearFocus();
                        tempView = null;
                    }
                    break;
            }
        }
    };

    private class SoftKeyboardChangesThread extends Thread
    {
        private AtomicBoolean started;
        private SoftKeyboardChanged mCallback;

        public SoftKeyboardChangesThread()
        {
            started = new AtomicBoolean(true);
        }

        public void setCallback(SoftKeyboardChanged mCallback)
        {
            this.mCallback = mCallback;
        }

        @Override
        public void run()
        {
            while(started.get())
            {
                // Wait until keyboard is requested to open
                synchronized(this)
                {
                    try
                    {
                        wait();
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }

                int currentBottomLocation = getLayoutCoordinates();

                // There is some lag between open soft-keyboard function and when it really appears.
                while(currentBottomLocation == layoutBottom && started.get())
                {
                    currentBottomLocation = getLayoutCoordinates();
                }

                if(started.get())
                    mCallback.onSoftKeyboardShow();

                // When keyboard is opened from EditText, initial bottom location is greater than layoutBottom
                // and at some moment equals layoutBottom.
                // That broke the previous logic, so I added this new loop to handle this.
                while(currentBottomLocation >= layoutBottom && started.get())
                {
                    currentBottomLocation = getLayoutCoordinates();
                }

                // Now Keyboard is shown, keep checking layout dimensions until keyboard is gone
                while(currentBottomLocation != layoutBottom && started.get())
                {
                    synchronized(this)
                    {
                        try
                        {
                            wait(500);
                        } catch (InterruptedException e)
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    currentBottomLocation = getLayoutCoordinates();
                }

                if(started.get())
                    mCallback.onSoftKeyboardHide();

                // if keyboard has been opened clicking and EditText.
                if(isKeyboardShow && started.get())
                    isKeyboardShow = false;

                // if an EditText is focused, remove its focus (on UI thread)
                if(started.get())
                    mHandler.obtainMessage(CLEAR_FOCUS).sendToTarget();
            }
        }

        public void keyboardOpened()
        {
            synchronized(this)
            {
                notify();
            }
        }

        public void stopThread()
        {
            synchronized(this)
            {
                started.set(false);
                notify();
            }
        }

    }
}

et dans votre Activity ou fragment, appelez cette méthode dans onCreate()

  private void hideAndShowKeyBOrd() {
        InputMethodManager im = (InputMethodManager) getActivity().getSystemService(Service.INPUT_METHOD_SERVICE);

/*
Instantiate and pass a callback
*/
        SoftKeyboard softKeyboard;
        softKeyboard = new SoftKeyboard(mainLayout, im);
        softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged() {

            @Override
            public void onSoftKeyboardHide() {
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                    }
                });
            }

            @Override
            public void onSoftKeyboardShow() {
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        if (viewV.getVisibility() == View.VISIBLE) {
                            viewV.setVisibility(View.GONE);
                        }
                    }
                });

            }
        });
    }

profitez de votre code :)

0
John smith