Android中的活动中的软键盘打开和关闭监听器

N S*_*rma 123 android android-softkeyboard android-edittext android-activity

我有一个Activity有5 EditText秒的地方.当用户点击第一个时EditText,软键盘会打开以在其中输入一些值.我想设置一些其他ViewGone对软键盘打开时的可见性,以及用户点击第一个时的可见性,以及当按下后面按钮EditText时软键盘关闭时EditText.然后我想将其他View人的可见性设置为可见.

EditText在Android中第一次点击软键盘时,是否有任何监听器或回调或任何黑客攻击?

Jaa*_*tum 86

这仅适用android:windowSoftInputMode于您的活动adjustResize在清单中设置的情况.您可以使用布局侦听器来查看键盘是否调整了活动的根布局.

我为我的活动使用类似下面的基类:

public class BaseActivity extends Activity {
    private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
            int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();

            LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(BaseActivity.this);

            if(heightDiff <= contentViewTop){
                onHideKeyboard();

                Intent intent = new Intent("KeyboardWillHide");
                broadcastManager.sendBroadcast(intent);
            } else {
                int keyboardHeight = heightDiff - contentViewTop;
                onShowKeyboard(keyboardHeight);

                Intent intent = new Intent("KeyboardWillShow");
                intent.putExtra("KeyboardHeight", keyboardHeight);
                broadcastManager.sendBroadcast(intent);
            }
        }
    };

    private boolean keyboardListenersAttached = false;
    private ViewGroup rootLayout;

    protected void onShowKeyboard(int keyboardHeight) {}
    protected void onHideKeyboard() {}

    protected void attachKeyboardListeners() {
        if (keyboardListenersAttached) {
            return;
        }

        rootLayout = (ViewGroup) findViewById(R.id.rootLayout);
        rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);

        keyboardListenersAttached = true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (keyboardListenersAttached) {
            rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下示例活动使用此选项在键盘显示时隐藏视图,并在隐藏键盘时再次显示键盘.

xml布局:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/rootLayout"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">              

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        >

        <!-- omitted for brevity -->

    </ScrollView>

    <LinearLayout android:id="@+id/bottomContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <!-- omitted for brevity -->

    </LinearLayout>

</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

活动:

public class TestActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        attachKeyboardListeners();
    }

    @Override
    protected void onShowKeyboard(int keyboardHeight) {
        // do things when keyboard is shown
        bottomContainer.setVisibility(View.GONE);
    }

    @Override
    protected void onHideKeyboard() {
        // do things when keyboard is hidden
        bottomContainer.setVisibility(View.VISIBLE);
    }        
}
Run Code Online (Sandbox Code Playgroud)

  • 嗨,你在Window.ID_ANDROID_CONTENT上使用了getTop().获得顶级对我不起作用.它总是在这里0,它的工作原理就是它应该使用getHeight()代替. (18认同)
  • @tsig 您的 +100 解决方案取决于特定屏幕。在平板电脑和 hdpi 手机上失败。我使用校正作为设备高度的 10%。这意味着如果视图高度低于 screenHeight - 10%,则键盘处于打开状态。否则键盘关闭。这是我在 onGlobalLayout 中的 contentViewTop: contentViewTop = (getWindow().getDecorView().getBottom() / 10) (5认同)
  • +1是的这是我的问题的完美解决方案. (3认同)

Gal*_*Rom 75

一块蛋糕与令人敬畏的KeyboardVisibilityEvent库:https: //android-arsenal.com/details/1/2519

KeyboardVisibilityEvent.setEventListener(
    getActivity(),
    new KeyboardVisibilityEventListener() {
        @Override
        public void onVisibilityChanged(boolean isOpen) {
            // write your code
        }
    });
Run Code Online (Sandbox Code Playgroud)

对于2.0.0,支持min SDK版本为14

  • 它仍然是硬编码的.多窗口?三星拆分视图?画中画模式?另外还有一个最小的单行键盘,下降到100dp以下.这里没有银弹...... (5认同)
  • 因为没有针对此问题的全部内容,所以这似乎是最容易实现的,只需返回您实际想要处理的代码即可:) (3认同)
  • 令人沮丧的是,这样的基本功能在 Android 中没有原生解决方案!谷歌似乎在新的 Android 版本中塞入了太多不必要的垃圾,但却没有解决如此重要的缺陷...... (3认同)

Com*_*Guy 65

正如维克拉姆在评论中指出的那样,检测软键盘是否显示或已经消失只能通过一些丑陋的黑客攻击.

也许在edittext上设置焦点监听器就足够了:

yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            //got focus
        } else {
            //lost focus
        }
   }
});
Run Code Online (Sandbox Code Playgroud)

  • 假设我单击edittext然后它将调用`setOnFocusChangeListener`侦听器然后我按回然后它关闭键盘但没有点击其他视图,现在我再次点击已经有焦点的相同edittext然后会发生什么? (26认同)
  • 伙计们不看这个答案,因为即使我不明白,他也会说些不同的东西. (4认同)
  • @Williams我不完全确定,但我怀疑`onFocusChange()`不会被调用. (3认同)
  • 无论如何,它对我不起作用...隐藏软键盘时,EditText上没有发生任何焦点更改...所以我无法从此监听器得到通知。 (2认同)
  • 如果用户只是关闭键盘(向下箭头)焦点仍位于 EditText 但键盘已关闭 (2认同)

M S*_*wat 46

对于活动:

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

                activityRootView.getWindowVisibleDisplayFrame(r);

                int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 100) { 
                 //enter your code here
                }else{
                 //enter code for hid
                }
            }
        });
Run Code Online (Sandbox Code Playgroud)

片段:

    view = inflater.inflate(R.layout.live_chat_fragment, null);
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                //r will be populated with the coordinates of your view that area still visible.
                view.getWindowVisibleDisplayFrame(r);

                int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 500) { // if more than 100 pixels, its probably a keyboard...

                }
            }
        });
Run Code Online (Sandbox Code Playgroud)

  • 用于活动,但不是与视图i比较屏幕尺寸.效果很好 (3认同)

Ric*_*ard 32

Jaap的答案不适用于AppCompatActivity.而是获取状态栏和导航栏等的高度,并与您的应用程序的窗口大小进行比较.

像这样:

    private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // navigation bar height
        int navigationBarHeight = 0;
        int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            navigationBarHeight = getResources().getDimensionPixelSize(resourceId);
        }

        // status bar height
        int statusBarHeight = 0;
        resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = getResources().getDimensionPixelSize(resourceId);
        }

        // display window size for the app layout
        Rect rect = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);

        // screen height - (user app height + status + nav) ..... if non-zero, then there is a soft keyboard
        int keyboardHeight = rootLayout.getRootView().getHeight() - (statusBarHeight + navigationBarHeight + rect.height());

        if (keyboardHeight <= 0) {
            onHideKeyboard();
        } else {
            onShowKeyboard(keyboardHeight);
        }
    }
};
Run Code Online (Sandbox Code Playgroud)


Pav*_*bik 11

你可以尝试一下:

private void initKeyBoardListener() {
    // ??????????? ???????? ??????????. 
    // Threshold for minimal keyboard height.
    final int MIN_KEYBOARD_HEIGHT_PX = 150;
    // ???? ???????? ?????? view. 
    // Top-level window decor view.
    final View decorView = getWindow().getDecorView();
    // ???????????? ?????????? ?????????. Register global layout listener.
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        // ??????? ????????????? ?????? ????. 
        // Retrieve visible rectangle inside window.
        private final Rect windowVisibleDisplayFrame = new Rect();
        private int lastVisibleDecorViewHeight;

        @Override
        public void onGlobalLayout() {
            decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
            final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();

            if (lastVisibleDecorViewHeight != 0) {
                if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) {
                    Log.d("Pasha", "SHOW");
                } else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) {
                    Log.d("Pasha", "HIDE");
                }
            }
            // ????????? ??????? ?????? view ?? ?????????? ??????.
            // Save current decor view height for the next call.
            lastVisibleDecorViewHeight = visibleDecorViewHeight;
        }
    });
}
Run Code Online (Sandbox Code Playgroud)


小智 6

下面的代码对我有用,

mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (mainLayout != null) {
                int heightDiff = mainLayout.getRootView().getHeight() - mainLayout.getHeight();
                if (heightDiff > dpToPx(getActivity(), 200)) { 
                   //keyboard is open
                } else {
                   //keyboard is hide
                }
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)


F.M*_*sir 6

对于在 Kotlin 内部片段中使用(这是一个常见的用例),使用库非常容易KeyboardVisibilityEvent

在 build.gradle 中:

implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:3.0.0-RC2'
Run Code Online (Sandbox Code Playgroud)

在片段中:

activity?.let {
    KeyboardVisibilityEvent.setEventListener(it,object: KeyboardVisibilityEventListener {
        override fun onVisibilityChanged(isOpen: Boolean) {
            if (isOpen) Toast.makeText(context,"Keyboard is opened",Toast.LENGTH_SHORT).show()
            else Toast.makeText(context,"Keyboard is closed",Toast.LENGTH_SHORT).show()
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

来源和学分


Vla*_*lad 5

你可以使用我的 Rx 扩展函数(Kotlin)。

/**
 * @return [Observable] to subscribe of keyboard visibility changes.
 */
fun AppCompatActivity.keyboardVisibilityChanges(): Observable<Boolean> {

    // flag indicates whether keyboard is open
    var isKeyboardOpen = false

    val notifier: BehaviorSubject<Boolean> = BehaviorSubject.create()

    // approximate keyboard height
    val approximateKeyboardHeight = dip(100)

    // device screen height
    val screenHeight: Int = getScreenHeight()

    val visibleDisplayFrame = Rect()

    val viewTreeObserver = window.decorView.viewTreeObserver

    val onDrawListener = ViewTreeObserver.OnDrawListener {

        window.decorView.getWindowVisibleDisplayFrame(visibleDisplayFrame)

        val keyboardHeight = screenHeight - (visibleDisplayFrame.bottom - visibleDisplayFrame.top)

        val keyboardOpen = keyboardHeight >= approximateKeyboardHeight

        val hasChanged = isKeyboardOpen xor keyboardOpen

        if (hasChanged) {
            isKeyboardOpen = keyboardOpen
            notifier.onNext(keyboardOpen)
        }
    }

    val lifeCycleObserver = object : GenericLifecycleObserver {
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event?) {
            if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
                viewTreeObserver.removeOnDrawListener(onDrawListener)
                source.lifecycle.removeObserver(this)
                notifier.onComplete()
            }
        }
    }

    viewTreeObserver.addOnDrawListener(onDrawListener)
    lifecycle.addObserver(lifeCycleObserver)

    return notifier
            .doOnDispose {
                viewTreeObserver.removeOnDrawListener(onDrawListener)
                lifecycle.removeObserver(lifeCycleObserver)
            }
            .onTerminateDetach()
            .hide()
}
Run Code Online (Sandbox Code Playgroud)

例子:

(context as AppCompatActivity)
                    .keyboardVisibilityChanges()
                    .subscribeBy { isKeyboardOpen ->
                        // your logic
                    }
Run Code Online (Sandbox Code Playgroud)


Nit*_*gdi 5

我迟到了,但我刚刚发现了一个非常方便的依赖项。使用它,您可以检查键盘的可见性,并使用一行代码使键盘“隐藏”和“随时显示”。

implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:3.0.0-RC2'
Run Code Online (Sandbox Code Playgroud)

然后您只需使用此代码段来检查键盘可见性。

KeyboardVisibilityEvent.setEventListener(this, new KeyboardVisibilityEventListener() {
        
@Override
  public void onVisibilityChanged(boolean isOpen) {

if (isOpen) 
  Toast.makeText(MainActivity.this, "keyboard opened",Toast.LENGTH_SHORT).show();
else 
  Toast.makeText(MainActivity.this, "keyboard hidden", Toast.LENGTH_SHORT).show();
}
});
Run Code Online (Sandbox Code Playgroud)

然后,如果您想在任何时间隐藏/显示键盘,那么您只需编写这些单行之一即可实现。

        UIUtil.showKeyboard(this,edittext_to_be_focused);
        UIUtil.hideKeyboard(this);
Run Code Online (Sandbox Code Playgroud)


小智 5

在 kotlin 中,您可以在您的活动中使用此代码

window.decorView.viewTreeObserver.addOnGlobalLayoutListener{
    val r = Rect()
    window.decorView.getWindowVisibleDisplayFrame(r)
 
        val height =window.decorView.height
        if(height - r.bottom>height*0.1399){
           //keyboard is open
      }else{
            //keyboard is close
      }
Run Code Online (Sandbox Code Playgroud)

  • 为什么是0.139?您能详细介绍一下这个数字吗? (9认同)