Android:检测软键盘打开

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3081276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:37:25  来源:igfitidea点击:

Android: Detect softkeyboard open

androidviewscroll

提问by Noah Seidman

When the soft keyboard opens I want a scroll view to scroll down to the bottom.

当软键盘打开时,我希望滚动视图向下滚动到底部。

For this I can use: fullScroll(View.FOCUS_DOWN);

为此,我可以使用: fullScroll(View.FOCUS_DOWN);

But how do I fire that command after the soft keyboard opening event triggers?

但是在软键盘打开事件触发后如何触发该命令?

采纳答案by Rich Schuler

Per this postand this poston android-developers it doesn't seem like it's possible to do what you want. You may want to re-examine your use case for what you're doing. Maybe one of the softInputModeflags will work for you.

根据这篇文章这篇关于 android-developers 的文章,似乎不可能做你想做的事。您可能想要重新检查您的用例以了解您正在做什么。也许其中一个softInputMode标志对你有用。

回答by BoD

Here is my solution:

这是我的解决方案:

1/ A simple interface

1/ 一个简单的界面

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

2/ A utility method (put it where you want, for instance in a class named KeyboardUtil)

2/ 一个实用方法(把它放在你想要的地方,例如在一个名为 的类中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/ Use from an Activity this way (a good place is in onCreate):

3/ 以这种方式从活动中使用(一个好地方是在 onCreate 中):

KeyboardUtil.setKeyboardVisibilityListener(this, mKeyboardVisibilityListener);

回答by yeradis

watching the date , possibly you have a solution for your question, otherwise:

看日期,可能你有你的问题的解决方案,否则:

Here is the same response i made to another question related : Is there a way to tell if the soft-keyboard is shown?

这是我对另一个相关问题的相同回答:有没有办法判断软键盘是否显示?

but i copy full response here to avoid dead links:

但我在此处复制完整回复以避免死链接:

Please check Configuration Changesfor your Activity

请检查您的活动的配置更改

This for your AndroidManifest.xml

这适用于您的AndroidManifest.xml

and this for your Activityclass http://developer.android.com/reference/android/app/Activity.html#onConfigurationChanged(android.content.res.Configuration)

这对于您的活动http://developer.android.com/reference/android/app/Activity.html#onConfigurationChanged(android.content.res.Configuration)

You will need to @Override the public method onConfigurationChanged(android.content.res.Configuration) of your Activity to be able to handle, for example, this values:
hardKeyboardHidden,
keyboard,
keyboardHidden

您需要@OverrideActivity的公共方法onConfigurationChanged(android.content.res.Configuration) 才能处理,例如,以下值:
hardKeyboardHidden
keyboard
keyboardHidden

For all possible values check http://developer.android.com/reference/android/content/res/Configuration.html

对于所有可能的值,请检查http://developer.android.com/reference/android/content/res/Configuration.html

You will see there something like this:

你会看到这样的事情:

HARDKEYBOARDHIDDEN_NO   
HARDKEYBOARDHIDDEN_UNDEFINED    
HARDKEYBOARDHIDDEN_YES  
KEYBOARDHIDDEN_NO   
KEYBOARDHIDDEN_UNDEFINED    
KEYBOARDHIDDEN_YES  
KEYBOARD_12KEY  
KEYBOARD_NOKEYS 
KEYBOARD_QWERTY 
KEYBOARD_UNDEFINED

Also there you will be able to read something like this:

此外,您还可以阅读以下内容:

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.

UPDATE:

更新:

Here is a specific sampleof what i′m talking about:

这是我正在谈论的具体示例

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

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

I hope this help you

我希望这对你有帮助

回答by Roberto Andrade

The only way I was able to work around this is by setting my activity's android:windowSoftInputMode="adjustResize" and then embed a custom "detector view" in the layout to handle a container size change and propagate that as a custom event (via a Listener) for soft keyboard on/off.

我能够解决这个问题的唯一方法是设置我的活动的 android:windowSoftInputMode="adjustResize",然后在布局中嵌入一个自定义的“检测器视图”来处理容器大小的变化并将其作为自定义事件传播(通过侦听器)用于打开/关闭软键盘。

The following post describes an approach to implementing it: EditText does not trigger changes when back is pressed

下面的帖子描述了一种实现它的方法:EditText 在按下后退时不会触发更改

回答by Ramón Pérez Silva

This works for me

这对我有用

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

Where parent is the main layout, viewToHide is the view that shows or hides when the keyboard is shown, and host,folder,user and pass are the EditText of my form.

其中 parent 是主要布局,viewToHide 是在显示键盘时显示或隐藏的视图,host、folder、user 和 pass 是我的表单的 EditText。

And this in the manifest

这在清单中

android:windowSoftInputMode="stateHidden|adjustResize"

Hope this help

希望这有帮助

回答by Grimmy

Here is my solution. It doesn't need android:windowSoftInputMode="adjustResize"

这是我的解决方案。它不需要 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);
    }
}

Then I've just extend my activity from this activity and override onKeyboardClosed/onKeyboardOpen methods.

然后我只是从这个活动扩展我的活动并覆盖 onKeyboardClosed/onKeyboardOpen 方法。

回答by venkat

@BoD's answerworks fine if I remove the following line.

如果我删除以下行,@BoD 的答案就可以正常工作。

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

回答by John smith

for this what i used to do same:

为此,我曾经做过同样的事情:

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

    }
}

and in your Activityor fragmentcall this method in onCreate()

并在您的Activityfragment调用此方法中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);
                        }
                    }
                });

            }
        });
    }

enjoy your code:)

享受你的代码:)