programing

Android 장치에 소프트웨어 키보드가 표시되는지 여부를 확인하려면 어떻게 해야 합니까?

powerit 2023. 10. 5. 23:36
반응형

Android 장치에 소프트웨어 키보드가 표시되는지 여부를 확인하려면 어떻게 해야 합니까?

Android에서 소프트웨어(일명 "소프트") 키보드가 화면에 보이는지 감지하는 방법이 있습니까?

저는 이 정도면 돼요.어쩌면 이것이 모든 버전에 항상 최선의 방법일지도 모릅니다.

onGlobalLayout 메서드가 여러 번 호출하기 때문에 키보드 가시성 속성을 만들고 이러한 변경 사항이 지연되는 것을 관찰하는 것이 효과적입니다.또한 장치 회전을 확인하는 것이 좋습니다.windowSoftInputMode그렇지 않습니다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)
            }
        }
    }
});

시도해 보십시오.

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

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

직접적인 방법은 없습니다 - 안드로이드 팀의 Dianne Hackborn이 응답한 http://groups.google.com/group/android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898a 을 참조하십시오.그러나 #onMeasure에서 윈도우 크기가 변경되었는지 확인하여 간접적으로 감지할 수 있습니다.Android에서 소프트웨어 키보드의 가시성을 확인하는 방법을 참조하십시오.

는 이것을 위해 사용할 수 있는 간단한 수업을 만들었습니다: https://github.com/ravindu1024/android-keyboardlistener .프로젝트에 복사만 하면 다음과 같이 사용할 수 있습니다.

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

새로운 기능과 함께WindowInsetsCompat안드로이드x 코어 릴리즈 1.5.0-alpha02에서는 아래와 같이 소프트 키보드의 가시성을 쉽게 확인할 수 있었습니다.

레딧 댓글에서 인용하기

val View.keyboardIsVisible: Boolean
    get() = WindowInsetsCompat
        .toWindowInsetsCompat(rootWindowInsets)
        .isVisible(WindowInsetsCompat.Type.ime())

이전 버전과의 호환성에 대한 몇 가지 참고 사항(릴리스 노트에서 인용)

새 기능

WindowInsetsCompatAPI는 안드로이드 11의 플랫폼에 있는 API로 업데이트되었습니다.여기에는 새로운 것이 포함됩니다.ime()화면 키보드의 가시성과 크기를 확인할 수 있는 inset type.

몇 가지 주의할 점은ime()타입, 그것은 당신의 Activity가 사용하고 있을 때 API 23+에서 매우 안정적으로 작동합니다.adjustResize윈도우 소프트 입력 모드.대신 사용하는 경우adjustPanmode, API 14로 안정적으로 돌아갈 수 있어야 합니다.

참고문헌

아주 쉬운

1. 루트 보기에 ID를 지정합니다.

rootView이 경우에 내 루트 뷰를 가리키는 뷰일 뿐입니다.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. 활동에서 루트 보기를 초기화합니다.

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

3. 를 사용하여 키보드가 열리거나 닫히는지 탐지getViewTreeObserver()

    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();
                
                if (heightDiff > 100) { // Value should be less than keyboard's height 
                    Log.e("MyActivity", "keyboard opened");
                } else { 
                    Log.e("MyActivity", "keyboard closed");
                }
            }
        });

그래서 오랫동안 내게 접근성 서비스, 창 삽입 장치, 화면 높이 감지 등을 가지고 놀다가 이것을 할 수 있는 방법을 찾은 것 같습니다.

면책 사항: Android의 숨겨진 방법을 사용하므로 일관성이 없을 수 있습니다.하지만, 제 테스트에서는 효과가 있는 것 같습니다.

메서드는 InputMethodManager#get입니다.입력 방법 창 표시높이(), 그리고 그것은 롤리팝(5.0) 때부터 존재했습니다.

현재 키보드의 높이(픽셀)를 반환하는 호출입니다.이론적으로 키보드의 높이는 0픽셀이 되어서는 안 되기 때문에 간단한 높이 검사를 했습니다(Kotlin에서).

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

저는 안드로이드 히든 API를 사용하여 히든 메소드를 호출할 때 반사를 피합니다(대부분 해킹/튜너 앱인 내가 개발하는 앱의 경우 많이 사용합니다). 하지만 이것은 반사를 통해서도 가능해야 합니다.

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

Androidx.core(버전 1.5.0-rc01)에서 WindowInsetsCompat을 사용할 수 있습니다.이 코드는 API 21 이상부터 동작합니다.코틀린 코드 예제:

ViewCompat.setOnApplyWindowInsetsListener(root) { v, insets ->
    val isKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
    if (isKeyboardVisible) {
    }
}

root은 활동의 root 보기입니다.

갱신하다

오늘은 키보드의 가시성을 감지하는 방법을 찾고 있었습니다.처음에는 이 코드가 작동하지 않았습니다.그래서 나는 다음과 같이 해야 했습니다.

  1. 더하다android:windowSoftInputMode="adjustResize"Android Manifest.xml 파일로 이동합니다.
xml
        <activity android:name="com.soumicslabs.activitykt.StartActivity"
            android:theme="@style/AccountKitTheme.Default"
          android:configChanges="orientation|screenSize"
          android:screenOrientation="portrait"
          android:windowSoftInputMode="adjustResize"
          />
  1. 에서 를 설정합니다WindowCompat.setDecorFitsSystemWindows(window, false)/시스템 않음을 즉, Android 를 는합니다.
        val window = this.window
        WindowCompat.setDecorFitsSystemWindows(window, false)  // <-- this tells android not to use system defaults, so we have to setup quite a lot of behaviors manually
  1. 마지막으로, 당신을 잡으세요.onApplyWindowInsetsListener:
val callBack = OnApplyWindowInsetsListener { view, insets ->
            val imeHeight = insets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom?:0
            Log.e("tag", "onKeyboardOpenOrClose imeHeight = $imeHeight")
// todo: logic
val isKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
    if (isKeyboardVisible) {
       // do something
    }else{
        // do something else
    }
    insets?: WindowInsetsCompat(null)
  }

ViewCompat.setOnApplyWindowInsetsListener(mainContainer, callBack)

저는 이게 통했어요.

저는 이것을 근거로 사용했습니다: https://rogerkeays.com/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;
}
}

그런 다음 이 방법을 썼습니다.

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;

}

그런 다음 모든 필드(EditText, AutoComplete)를 테스트할 수 있습니다.소프트키보드를 열었을 가능성이 있는 TextView(텍스트 보기) 등:

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

더해서 이상적인 해결책은 아니지만, 일은 완수할 수 있습니다.

showSoft의 콜백 결과를 사용할 수 있습니다.()를 입력하고 SoftInput()을 숨겨 키보드 상태를 확인합니다.전체 세부 정보 및 예제 코드:

https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android

이제 마침내 코틀린을 기반으로 하는 안드로이드 R에서 직접적인 방법이 있습니다.

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

이것은 제가 필요로 하는 요구사항에 비해 훨씬 덜 복잡했습니다.도움이 되기를 바랍니다.

주 활동에 대해:

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

기본 primative boolean 값 form mKeyboardStatus는 false로 초기화됩니다.

다음과 같이 값을 확인하고 필요한 경우 조치를 수행합니다.

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

키보드 상태를 확인해야 할 경우 이 작업을 수행해야 합니다.

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

에.UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP100 100과 dip은 dpToPx하는 Anko func다를 입니다.

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

이 답변을 참고하실 수 있습니다 - https://stackoverflow.com/a/24105062/3629912

전 매번 효과가 있었어요.

adb shell dumpsys window InputMethod | grep "mHasSurface"

소프트웨어 키보드가 보이면 true로 돌아갑니다.

다음과 같이 GlobalLayoutListener를 설정하여 이 작업을 수행했습니다.

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

이 코드를 사용해 보십시오. 키보드가 있으면 정말로 작동합니다.표시된 다음 이 함수는 참 값을 반환합니다.

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

안드로이드 소프트웨어 키보드는 입력 가능한 이벤트가 있을 때만 볼 수 있습니다.즉, EditText(텍스트 편집)이 포커스를 맞출 때만 키보드가 표시됩니다.즉, 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;
    }
});

이제 클래스의 어디에서나 isKeyBoardVisible 변수를 사용하여 키보드가 열리거나 열리지 않는 날씨를 파악할 수 있습니다.저한테는 잘 통했어요.

참고: InputMethodManager를 사용하여 키보드를 프로그래밍 방식으로 열면 OnFocusChangeListener를 호출하지 않으므로 이 프로세스가 작동하지 않습니다.

모든 답변에 감사드립니다. 저는 제 상황에 맞게 이해합니다.

/**
 * Add global layout listener to observe system keyboard visibility
 */
private void initObserverForSystemKeyboardVisibility() {
    getRootView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            //Add your own code here
            Log.d("TEST_CODE", "isSystemKeyboardVisible:" + isSystemKeyboardVisible())
        }
    });
}


/**
 * Check system keyboard visibility
 * @return true if visible
 */
public boolean isSystemKeyboardVisible() {
    try {
        final InputMethodManager manager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        final Method windowHeightMethod = InputMethodManager.class.getMethod("getInputMethodWindowVisibleHeight");
        final int height = (int) windowHeightMethod.invoke(manager);
        return height > 0;
    } catch (Exception e) {
        return false;
    }
}
private fun isKeyboardVisible(rootView: View) =
    ViewCompat.getRootWindowInsets(rootView)!!.isVisible(WindowInsetsCompat.Type.ime())

내 경우엔 하나밖에 없었거든요EditText제 레이아웃을 관리하기 위해서 이 해결책을 생각해 냈습니다.잘 작동합니다. 기본적으로 관습입니다.EditText포커스가 변경되거나 Back/Done 버튼을 누르면 포커스를 수신하고 로컬 브로드캐스트를 전송합니다.다를 .View서를 요.android:focusable="true"그리고.android:focusableInTouchMode="true"clearFocus()포커스가 첫 번째 포커스 가능 뷰로 다시 지정됩니다.더미 뷰 예제:

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

추가정보

레이아웃 변경의 차이를 감지하는 솔루션은 화면 밀도에 따라 크게 달라지기 때문에 잘 작동하지 않습니다. 특정 장치에서는 100px가 많이 나올 수 있고 다른 장치에서는 위양성을 얻을 수 없기 때문입니다.또한 공급업체마다 키보드가 다릅니다.

@bohdan-oliynk의 답변을 바탕으로 조금 더 압축된 Kotlin 버전

private const val KEYBOARD_VISIBLE_THRESHOLD_DP = 100

fun Activity.isKeyboardOpen(): Boolean {
    fun convertDpToPx(value: Int): Int =
        (value * Resources.getSystem().displayMetrics.density).toInt()

    val rootView = findViewById<View>(android.R.id.content)
    val visibleThreshold = Rect()
    rootView.getWindowVisibleDisplayFrame(visibleThreshold)
    val heightDiff = rootView.height - visibleThreshold.height()

    val accessibleValue = convertDpToPx(KEYBOARD_VISIBLE_THRESHOLD_DP)

    return heightDiff > accessibleValue
}

fun Activity.isKeyboardClosed(): Boolean {
    return isKeyboardOpen().not()
}

2023년에 드디어 공식적인 지원이 시작되었습니다!

여기 서류가 있습니다.

키보드가 보이는지 확인하려면 다음 작업을 수행합니다.

val insets = ViewCompat.getRootWindowInsets(view) ?: return
val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom

키보드 가시성의 변화를 들으려면 다음을 수행합니다.

ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
  val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
  val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
  insets
}

참고: Google은 앱이 제대로 작동하려면 edge to edge를 표시하도록 구성하는 것이 좋습니다.또한 "이 AndroidX 구현과 최상의 하위 호환성을 달성하기 위해 다음과 같이 말합니다.android:windowSoftInputMode="adjustResize"Android Manifest.xml 의합니다"

안드로이드에서는 ADB 셸을 통해 탐지할 수 있습니다.저는 이 방법을 쓰고 사용했습니다.

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

않습니다 @iWantScala 의.
rootView.getRootView().getHeight()는 한 값를 갖습니다.

한 가지 방법은 두 개의 변수를 정의하는 것입니다.

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

글로벌 리스너 추가

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

그다음에 체크

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

잘 통합니다

이것을 알아낼 수 있는 직접적인 방법이 있습니다.또한 레이아웃 변경이 필요하지 않습니다.
그래서 몰입형 전체 화면 모드에서도 작동합니다.
하지만 안타깝게도 모든 기기에서 작동하지는 않습니다.따라서 장치를 사용하여 테스트해야 합니다.

비결은 소프트 키보드를 숨기거나 보여주고 그 시도의 결과를 캡처하는 것입니다.
올바르게 작동하면 키보드가 실제로 표시되거나 숨겨지지 않습니다.우리는 단지 주를 요청할 뿐입니다.

최신 상태를 유지하려면 핸들러를 사용하여 200밀리초마다 이 작업을 반복하기만 하면 됩니다.

아래의 구현은 한 번의 확인만 수행합니다.
여러 번 검사를 수행하는 경우 모든 (_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;
        }
    }
};

소프트키보드가 보이는지 확인할 수 있는 방법은 다음과 같습니다.

  1. ActivityManager.getRunningServices(max_count_of_services)를 사용하여 시스템에서 실행 중인 서비스를 확인합니다.
  2. 반환된 Activity Manager에서.ServiceInfo 인스턴스를 실행 중이며 clientCount 값에서 소프트 키보드 서비스를 확인합니다.
  3. 앞에서 설명한 clientCount는 소프트 키보드가 표시될 때마다 증가합니다.예를 들어 clientCount가 처음에 1인 경우 키보드가 표시될 때 2가 됩니다.
  4. 키보드 해지 시 clientCount가 감소합니다.이 경우 1로 재설정됩니다.

인기 있는 키보드 중 일부는 클래스에 특정 키워드를 가지고 있습니다.이름:

  1. Google AOSP = IME
  2. 스와이프 = IME
  3. 스위프트키 = 키보드 서비스
  4. Fleksy = 키보드
  5. Adaptxt = IME(KPTAdaptxTIME)
  6. Smart = 키보드(스마트 키보드)

ActivityManager에서.RunningServiceInfo 클래스 이름에서 위 패턴을 확인합니다.그리고 활동 매니저.서비스 실행 중키보드가 시스템에 바인딩되어 있음을 나타내는 Info의 clientPackage= android.

위에 언급된 정보들은 소프트 키보드가 보이는지를 알아내기 위한 엄격한 방법으로 결합될 수 있습니다.

코틀린으로 답변을 전환했는데 코틀린 사용자에게 도움이 되었으면 합니다.

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

            }
        }
    }
}

앱에서 안드로이드R용 apis를 지원한다면 아래 방법을 사용할 수 있습니다.

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

참고: 안드로이드 R에서만 사용 가능하며 안드로이드 버전 이하에서는 다른 답변을 따라야 합니다. 그렇지 않으면 업데이트하겠습니다.

adjustNothing 플래그의 활동 및 라이프사이클 이벤트와 함께 작동합니다.코틀린과 함께:

/**
 * 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)
    }
}

키보드 위에서 항상 보기를 유지하는 유용한 방법

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

전체 보기 경계를 가져오는 위치

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

전체 화면 크기를 얻는 위치

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
}

where 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
}

언급URL : https://stackoverflow.com/questions/4745988/how-do-i-detect-if-software-keyboard-is-visible-on-android-device-or-not

반응형