安卓EditText,软键盘显示/隐藏事件?

46

如何捕获软键盘显示或隐藏的事件以供EditText使用?


你已经解决了这个问题吗?能否请您分享一下您的经验? - woodshy
1
虽然这是一篇旧帖子,但在类似的情况下,这个答案更为合适:https://dev59.com/Ym855IYBdhLWcg3wfUZM#4365637 - Pedro Loureiro
3
这是一个更好的解决方案。 https://dev59.com/WHI95IYBdhLWcg3wyRM0 - Zain Ali
7个回答

30

嗨,我使用了以下解决方法:

由于我的内容视图是LinearLayout的子类(也可以是任何其他视图或视图组),我重写了onMeasure方法,如下所示:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
    final int actualHeight = getHeight();

    if (actualHeight > proposedheight){
        // Keyboard is shown
    } else {
        // Keyboard is hidden
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

以下方法可以帮助我在键盘显示时隐藏一些控件,否则恢复显示。

希望对你有所帮助。


1
在哪里添加这个覆盖?我有一个从LinearLayout膨胀的SherlockActivty,但是一直得到该方法未定义于类的错误。 - David Homes
@dhomes 这不是 Activity 的方法,而是 View 的方法。创建您自己的“View”,并覆盖此方法。 - Dmitry Zaytsev
在某些设备(如三星),预测文本功能会对该解决方案造成问题。我通过将我的EditText的inputType设置为"textVisiblePassword"来禁用它来解决了这个问题。 - adamdport

18

实际上并不存在需要捕获的事件。输入法只是在显示和隐藏其窗口;由此产生的反馈是窗口管理器会使你自己的窗口内容重新调整大小,如果你处于调整大小模式下。


3
如何获取窗口内容大小调整事件? - DiveInto

4
我通过使用onGlobalLayoutListener解决了这个问题:
 final View activityRootView = findViewById(R.id.top_root);
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();

                if (heightDiff > 100) {
                    // keyboard is up
                } else {
                    // keyboard is down
                }
            }
        });

这里的activityRootView是您的Activity的根视图。


2
在我的情况下,我想在软键盘显示时隐藏底部栏。我认为最好的方法是当布局大小小于正常布局大小的百分之一时,只需隐藏该栏。因此,我使用了这个解决方案,考虑到软键盘通常占据20%或更多的屏幕高度,它可以很好地工作。只需将百分比常量更改为您认为合适的任何值即可。它需要在清单中设置属性android:windowSoftInputMode="adjustResize",并且布局必须是根布局才能工作。
您可以从任何您想要的布局中进行扩展,而不仅仅是RelativeLayout。
public class SoftKeyboardLsnedRelativeLayout extends RelativeLayout {
    private boolean isKeyboardShown = false;
    private List<SoftKeyboardLsner> lsners=new ArrayList<SoftKeyboardLsner>();
    private float layoutMaxH = 0f; // max measured height is considered layout normal size
    private static final float DETECT_ON_SIZE_PERCENT = 0.8f;

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

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

    @SuppressLint("NewApi")
    public SoftKeyboardLsnedRelativeLayout(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int newH = MeasureSpec.getSize(heightMeasureSpec);
        if (newH > layoutMaxH) {
            layoutMaxH = newH;
        }
        if (layoutMaxH != 0f) {
            final float sizePercent = newH / layoutMaxH;
            if (!isKeyboardShown && sizePercent <= DETECT_ON_SIZE_PERCENT) {
                isKeyboardShown = true;
                for (final SoftKeyboardLsner lsner : lsners) {
                    lsner.onSoftKeyboardShow();
                }
            } else if (isKeyboardShown && sizePercent > DETECT_ON_SIZE_PERCENT) {
                isKeyboardShown = false;
                for (final SoftKeyboardLsner lsner : lsners) {
                    lsner.onSoftKeyboardHide();
                }
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    public void addSoftKeyboardLsner(SoftKeyboardLsner lsner) {
        lsners.add(lsner);
    }

    public void removeSoftKeyboardLsner(SoftKeyboardLsner lsner) {
        lsners.remove(lsner);
    }

    // Callback
    public interface SoftKeyboardLsner {
        public void onSoftKeyboardShow();
        public void onSoftKeyboardHide();
    }
}

Example:

layout/my_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<yourclasspackage.SoftKeyboardLsnedRelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/myLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    ...
</yourclasspackage.SoftKeyboardLsnedRelativeLayout>

MyActivity.java

public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        SoftKeyboardLsnedRelativeLayout layout = (SoftKeyboardLsnedRelativeLayout) findViewById(R.id.myLayout);
        layout.addSoftKeyboardLsner(new SoftKeyboardLsner() {
            @Override
            public void onSoftKeyboardShow() {
                Log.d("SoftKeyboard", "Soft keyboard shown");
            }

            @Override
            public void onSoftKeyboardHide() {
                Log.d("SoftKeyboard", "Soft keyboard hidden");
            }
        });
    }
}

1
尝试使用以下方法:showSoftInput(View, int, ResultReceiver)hideSoftInputFromWindow(IBinder, int, ResultReceiver)。您可以重写ResultReceiver类的onReceiveResult(int resultCode, Bundle resultData)方法来处理显示/隐藏事件。

1
这样,只有在完成所请求的操作时,您才会收到回调。但不会在将来发生任何事件时接收到回调。如果我们在向 showSoftInput 传递 ResultReceiver 时能够接收用户的隐藏事件(例如返回按钮),那就太好了,但实际上并非如此。 - TWiStErRob

0

许多Android开发人员喜欢根据虚拟键盘是否显示来更改布局。因此,您可以查看Android:检测软键盘打开以获取解决方案。对我而言,它很有效,我认为它也非常有用。


-6
您可以通过覆盖活动的onConfigurationChanged方法来捕获此内容:
@Override
public void onConfigurationChanged(Configuration newConfig) {
   super.onConfigurationChanged(newConfig);

   if(newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
      ((SherlockFragmentActivity)getActivity()).getSupportActionBar().hide();
   }
   else if(newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES){
      ((SherlockFragmentActivity)getActivity()).getSupportActionBar().show();
   }
}

1
这适用于硬键盘,而OP特别要求softKeyboard事件。 - verybadalloc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接