sourcetip

안드로이드에서 소프트웨어 키보드의 가시성을 확인하는 방법은 무엇입니까?

fileupload 2023. 6. 12. 21:51
반응형

안드로이드에서 소프트웨어 키보드의 가시성을 확인하는 방법은 무엇입니까?

소프트웨어 키보드가 표시되는지 확인하는 매우 간단한 작업을 수행해야 합니다.안드로이드에서 이것이 가능합니까?

새로운 답변 2012년 1월 25일 추가

아래 답변을 작성한 이후, 누군가가 버전 1부터 SDK에 숨어있는 API인 ViewTreeObserver와 친구들의 존재를 저에게 알려주었습니다.

사용자 정의 레이아웃 유형을 요구하는 것보다 훨씬 간단한 해결책은 활동의 루트 보기에 알려진 ID를 지정하는 것입니다.@+id/activityRootGlobalLayoutListener를 ViewTreeObserver에 연결하고 여기서 활동의 보기 루트와 창 크기 간의 크기 차이를 계산합니다.

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
        if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard...
            // ... do something here
        }
     }
});

다음과 같은 유틸리티 사용:

public static float dpToPx(Context context, float valueInDp) {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}

진정!

참고: 응용 프로그램이 Android 매니페스트에서 이 플래그를 설정해야 합니다.android:windowSoftInputMode="adjustResize"그렇지 않으면 위의 해결책이 작동하지 않습니다.

원답

네, 가능합니다. 하지만 그것은 예상보다 훨씬 어렵습니다.

하는 써야 한다면 (이지만) 를 사용자 입니다.onMeasure()기본적인 논리는 레이아웃이 창의 전체 영역보다 훨씬 적게 채워지는 경우 소프트 키보드가 표시될 수 있습니다.

import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.LinearLayout;

/*
 * LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when 
 * the soft keyboard is shown and hidden (something Android can't tell you, weirdly). 
 */

public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {

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

    public interface Listener {
        public void onSoftKeyboardShown(boolean isShowing);
    }
    private Listener listener;
    public void setListener(Listener listener) {
        this.listener = listener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height = MeasureSpec.getSize(heightMeasureSpec);
        Activity activity = (Activity)getContext();
        Rect rect = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int statusBarHeight = rect.top;
        int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
        int diff = (screenHeight - statusBarHeight) - height;
        if (listener != null) {
            listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);       
    }

    }

그러면 활동 수업에서...

public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);
        mainLayout.setListener(this);
        ...
    }


    @Override
    public void onSoftKeyboardShown(boolean isShowing) {
        // do whatever you need to do here
    }

    ...
}

그래서 바라건대 이것이 누군가를 도와주기를 바랍니다.

루벤 스크래튼이 제시한 새로운 답변은 훌륭하고 정말 효율적이지만, 창을 설정해야만 작동합니다.소프트크기를 조정하려면 모드를 입력합니다.adjustPan으로 설정해도 코드 스니펫을 사용하여 키보드를 볼 수 있는지 여부를 감지할 수 없습니다.이 문제를 해결하기 위해 위의 코드를 약간 수정했습니다.

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    activityRootView.getWindowVisibleDisplayFrame(r);
   
    int heightDiff = activityRootView.getRootView().getHeight() - r.height();
    if (heightDiff > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
        ... do something here
    }
 }
}); 

컴퓨터의 관점에서 그것은 영원했지만 이 질문은 여전히 믿을 수 없을 정도로 관련이 있습니다!

그래서 저는 위의 답변들을 받아들였고, 그것들을 조합하고 다듬었습니다.

public interface OnKeyboardVisibilityListener {


    void onVisibilityChanged(boolean visible);
}

public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
    final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);

    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        private boolean wasOpened;

        private final int DefaultKeyboardDP = 100;

        // From @nathanielwolf answer...  Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
        private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);

        private final Rect r = new Rect();

        @Override
        public void onGlobalLayout() {
            // Convert the dp to pixels.
            int estimatedKeyboardHeight = (int) TypedValue
                    .applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());

            // Conclude whether the keyboard is shown or not.
            activityRootView.getWindowVisibleDisplayFrame(r);
            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            boolean isShown = heightDiff >= estimatedKeyboardHeight;

            if (isShown == wasOpened) {
                Log.d("Keyboard state", "Ignoring global layout change...");
                return;
            }

            wasOpened = isShown;
            listener.onVisibilityChanged(isShown);
        }
    });
}

나에게 효과가 있습니다 :)

참고: 기본 키보드를 사용하는 경우DP가 장치의 재생 값에 맞지 않으며 모든 사용자가 값을 알 수 있도록 댓글을 게시합니다.결국 우리는 모든 장치에 맞는 정확한 값을 얻을 것입니다!

자세한 내용은 Cyborg의 구현을 참조하십시오.

답변이 늦어서 죄송합니다. 청취자에게 알림과 함께 열기/닫기 이벤트를 처리할 수 있는 작은 도우미 클래스를 만들었습니다. 누군가 도움이 될 수 있습니다.

import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;

import java.util.LinkedList;
import java.util.List;

public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {

    public interface SoftKeyboardStateListener {
        void onSoftKeyboardOpened(int keyboardHeightInPx);
        void onSoftKeyboardClosed();
    }

    private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
    private final View activityRootView;
    private int        lastSoftKeyboardHeightInPx;
    private boolean    isSoftKeyboardOpened;

    public SoftKeyboardStateWatcher(View activityRootView) {
        this(activityRootView, false);
    }

    public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
        this.activityRootView     = activityRootView;
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        final Rect r = new Rect();
        //r will be populated with the coordinates of your view that area still visible.
        activityRootView.getWindowVisibleDisplayFrame(r);

        final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
            isSoftKeyboardOpened = true;
            notifyOnSoftKeyboardOpened(heightDiff);
        } else if (isSoftKeyboardOpened && heightDiff < 100) {
            isSoftKeyboardOpened = false;
            notifyOnSoftKeyboardClosed();
        }
    }

    public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
    }

    public boolean isSoftKeyboardOpened() {
        return isSoftKeyboardOpened;
    }

    /**
     * Default value is zero {@code 0}.
     *
     * @return last saved keyboard height in px
     */
    public int getLastSoftKeyboardHeightInPx() {
        return lastSoftKeyboardHeightInPx;
    }

    public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.add(listener);
    }

    public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.remove(listener);
    }

    private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
        this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;

        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardOpened(keyboardHeightInPx);
            }
        }
    }

    private void notifyOnSoftKeyboardClosed() {
        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardClosed();
            }
        }
    }
}

사용 예:

final SoftKeyboardStateWatcher softKeyboardStateWatcher 
    = new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);

// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks

고밀도 장치에서 소프트 키보드의 가시성을 잘못 감지하지 않도록 하기 위한 몇 가지 개선 사항:

  1. 높이 차이의 임계값은 128픽셀이 아닌 128dp로 정의되어야 합니다.
    측정 기준 및 그리드에 대한 Google 설계 문서참조하십시오. 48dp는 터치 개체에 적합한 크기이고 32dp는 버튼에 대해 최소입니다.일반 소프트 키보드에는 키 버튼이 4줄 포함되어야 하므로 최소 키보드 높이는 32dp * 4 = 128dp여야 합니다. 즉, 임계값 크기는 장치 밀도를 곱하여 픽셀로 전송해야 합니다.xxxhdpi 장치(밀도 4)의 경우 소프트 키보드 높이 임계값은 128 * 4 = 512 픽셀이어야 합니다.

  2. 루트 뷰와 해당 표시 영역 사이의 높이 차이:
    루트 뷰 높이 - 상태 막대 높이 - 가시 프레임 높이 = 루트 뷰 하단 - 가시 프레임 하단. 상태 막대 높이는 루트 뷰 가시 프레임 상단과 같기 때문입니다.

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

와우, 좋은 소식이 있습니다 Android Geeks.그리고 이제 옛날 방식과 작별할 시간입니다.먼저 공식 릴리스 노트를 추가하여 이러한 방법/클래스를 읽고 더 자세히 알아본 다음 이러한 놀라운 방법/클래스를 확인합니다.

참고 사항:클래스/메소드가 릴리스될 때까지 릴리스 앱에 추가하지 마십시오.

키보드 가시성 확인 방법

val insets = ViewCompat.getRootWindowInsets(view)
val isKeyboardVisible = insets.isVisible(Type.ime())

기타 유틸리티가 거의 없음

키보드 높이를 가져오는 방법

val insets = ViewCompat.getRootWindowInsets(view)
val keyboardHeight = insets.getInsets(Type.ime()).bottom

키보드 표시/숨기기 방법

val controller = view.windowInsetsController

// Show the keyboard
controller.show(Type.ime())

// Hide the keyboard
controller.hide(Type.ime())

참고: WindowInsetsController는 API-30에 추가되었으므로 이전 버전과 호환되는 클래스를 사용할 수 없을 때까지 기다립니다.

키보드 숨기기/표시 이벤트 청취 방법

ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
    val isKeyboardVisible = insets.isVisible(Type.ime())
    if (isKeyboardVisible) {
        // Do it when keyboard is being shown
    } else {
        // Do it when keyboard is hidden
    }

    // Return the insets to keep going down this event to the view hierarchy
    insets
}

키보드를 숨기고 소프트 입력 상태를 동시에 확인해야 하는 경우 다음 솔루션을 사용합니다.

public boolean hideSoftInput() {
    InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
    return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}

이 메서드는 숨기기 전에 키보드가 표시된 경우 true를 반환합니다.

시간을 좀 들여서 알아냈어요몇 가지 캐스트 예외를 실행했지만 layout.xml의 LinearLayout을 클래스 이름으로 바꿀 수 있다는 것을 알게 되었습니다.

다음과 같이:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
    xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">

<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:id="@+id/rlMaster" >
    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>

          ....

</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>    


</LinearLayout>

그러면 캐스팅 문제가 발생하지 않습니다.

모든 페이지에서 이 작업을 수행하지 않으려면 "MasterPage in Android"를 사용하는 것이 좋습니다.다음 링크를 참조하십시오. http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx

와이파이 키보드와 같은 일부 키보드의 높이가 0이기 때문에 요소의 높이를 확인하는 것은 신뢰할 수 없습니다.

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

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

활동의 decorView를 사용하여 소프트키보드의 숨김을 관찰할 수 있습니다.

public final class SoftKeyboardUtil {
    public static final String TAG = "SoftKeyboardUtil";
    public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
        final View decorView = activity.getWindow().getDecorView();
        decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect rect = new Rect();
                decorView.getWindowVisibleDisplayFrame(rect);
                int displayHight = rect.bottom - rect.top;
                int hight = decorView.getHeight();
                boolean hide = (double)displayHight / hight > 0.8 ;
                if(Log.isLoggable(TAG, Log.DEBUG)){
                    Log.d(TAG ,"DecorView display hight = "+displayHight);
                    Log.d(TAG ,"DecorView hight = "+ hight);
                    Log.d(TAG, "softkeyboard visible = " + !hide);
                }

                listener.onSoftKeyBoardVisible(!hide);

            }
        });
    }



    public interface OnSoftKeyBoardHideListener{
        void onSoftKeyBoardVisible(boolean visible);
    }
}

차이 코딩을 가정하는 대신에, 저는 제 애플리케이션에 메뉴 옵션이 있었기 때문에 이런 것을 했습니다.

final View root= findViewById(R.id.myrootview); 
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
    public void onGlobalLayout() {
        int heightDiff = root.getRootView().getHeight() - root.getHeight();

        Rect rectgle= new Rect();
        Window window= getWindow();
        window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
        int contentViewTop=                     
          window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
        if(heightDiff <= contentViewTop){
            //Soft KeyBoard Hidden
        }else{
            //Soft KeyBoard Shown
        }
     }
});

포함된 , , 이션은솔과만 합니다.API >= 21(Android L)이BottomNavigationViewLinearLayout키보드가 표시될 때 이를 숨겨야 합니다.

> LinearLayout
  > ContentView
  > BottomNavigationView

당신이 해야 할 일은 단지 확장하는 것입니다.LinearLayout다음과 같은 방식으로:

public class KeyboardAwareLinearLayout extends LinearLayout {
    public KeyboardAwareLinearLayout(Context context) {
        super(context);
    }

    public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public KeyboardAwareLinearLayout(Context context,
                                     @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
                                     int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        int childCount = getChildCount();
        for (int index = 0; index < childCount; index++) {
            View view = getChildAt(index);
            if (view instanceof BottomNavigationView) {
                int bottom = insets.getSystemWindowInsetBottom();
                if (bottom >= ViewUtils.dpToPx(200)) {
                    // keyboard is shown
                    view.setVisibility(GONE);
                } else {
                    // keyboard is hidden
                    view.setVisibility(VISIBLE);
                }
            }
        }
        return insets;
    }
}

크게 입니다..bottomvalue.value.value.

이 될 수 요, 여에도될수있숨있방다습니이법진겨.InputMethodManager.getInputMethodWindowVisibleHeight그런데 왜 숨겨져 있는지 모르겠어요.

import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager

class SoftKeyboardStateWatcher(private val ctx: Context) {
  companion object {
    private const val DELAY = 10L
  }

  private val handler = Handler()
  private var isSoftKeyboardOpened: Boolean = false

  private val height: Int
    get() {
      val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
      val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
      method.isAccessible = true
      return method.invoke(imm) as Int
    }

  private val task: Runnable by lazy {
    Runnable {
      start()
      if (!isSoftKeyboardOpened && height > 0) {
        isSoftKeyboardOpened = true
        notifyOnSoftKeyboardOpened(height)
      } else if (isSoftKeyboardOpened && height == 0) {
        isSoftKeyboardOpened = false
        notifyOnSoftKeyboardClosed()
      }
    }
  }

  var listener: SoftKeyboardStateListener? = null

  interface SoftKeyboardStateListener {
    fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
    fun onSoftKeyboardClosed()
  }

  fun start() {
    handler.postDelayed(task, DELAY)
  }

  fun stop() {
    handler.postDelayed({
      if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
    }, DELAY * 10)
  }

  private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
    listener?.onSoftKeyboardOpened(keyboardHeightInPx)
  }

  private fun notifyOnSoftKeyboardClosed() {
    listener?.onSoftKeyboardClosed()
  }
}

저는 @Rewen_Scratton의 방법과 @Yogesh의 방법의 조합이 가장 잘 작동하는 것으로 보인다는 것을 발견했습니다.이들의 방법을 결합하면 다음과 같은 결과를 얻을 수 있습니다.

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
       // ... do something here
    }
  }
});

이러한 솔루션 중 어느 것도 현재 상태로는 롤리팝에 적용되지 않을 것입니다.activityRootView.getRootView().getHeight()에는 버튼 표시줄의 높이가 포함되어 있지만 보기는 측정하지 않습니다.저는 롤리팝과 함께 작업할 수 있도록 위의 가장 좋은/간단한 솔루션을 적용했습니다.

    final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    activityRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
    Resources res = getResources();
    // The status bar is 25dp, use 50dp for assurance
    float maxDiff =
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());

    //Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      float buttonBarHeight =
          TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
      maxDiff += buttonBarHeight;
    }
    if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
      ...do something here
    }
  }
});

저는 방금 위의 솔루션 대부분을 사용하는 동안 고정 번호를 추가하는 것을 제안하는 버그를 발견했습니다.

S4는 dpi가 높아서 내비게이션 바의 높이가 100px이므로 내 앱은 키보드가 항상 열려 있다고 생각합니다.

따라서 모든 새로운 고해상도 전화기가 출시됨에 따라 하드 코드화된 값을 사용하는 것은 장기적으로 좋은 생각이 아니라고 생각합니다.

다양한 화면과 기기를 테스트한 후 찾은 더 나은 접근법은 백분율을 사용하는 것이었습니다.decorView와 앱 콘텐츠 간의 차이를 확인한 후 해당 차이의 비율을 확인합니다.제가 얻은 통계에서 대부분의 내비게이션 바(크기, 해상도 등에 관계없이).)는 화면의 3%에서 5%를 차지합니다.키보드가 열려 있는 것처럼 화면의 47%에서 55%를 차지했습니다.

결론적으로 저의 해결책은 차이가 10% 이상인지 확인한 후 키보드가 열려 있다고 가정하는 것이었습니다.

저는 루반의 답변을 약간 변형하여 사용했는데, 특정 상황, 특히 고해상도 장치에서 더 도움이 되는 것으로 입증되었습니다.

final View activityRootView = findViewById(android.R.id.content);
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
                }
            }
        });

컴퓨터의 관점에서 볼 때 그것은 영원했지만 이 질문은 여전히 믿을 수 없을 정도로 관련이 있습니다!그래서 저는 위의 답변들을 받아들였고, 그것들을 조합하고 다듬었습니다.

public interface OnKeyboardVisibilityListener {
    void onVisibilityChanged(boolean visible);
}

public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
    final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        private boolean wasOpened;

    private final Rect r = new Rect();

        @Override
        public void onGlobalLayout() {
            activityRootView.getWindowVisibleDisplayFrame(r);

            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            boolean isOpen = heightDiff > 100;
            if (isOpen == wasOpened) {
                logDebug("Ignoring global layout change...");
                return;
            }

            wasOpened = isOpen;
            listener.onVisibilityChanged(isOpen);
        }
    });
}

저한테는 효과가 있어요.

사용해 보십시오.

final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.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.
        activityRootView.getWindowVisibleDisplayFrame(r);

        int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
             // ... do something here ... \\
        }
    }
});

문서에 따르면..https://developer.android.com/reference/androidx/core/view/WindowInsetsCompat

릴리스 노트를 확인합니다.https://developer.android.com/jetpack/androidx/releases/core#1.5.0-alpha02

상태를 하려면 현재키드상보다오사시십용음하을려면태를 할 수 .getRootWindowInsets그리고 나서 전화하세요.isVisible()함수, IME 유형을 전달합니다.

val windowinsetscompat = ViewCompat.getRootWindowInsets(view)
val imeVisible = windowinsetscompat.isVisible(Type.ime())

에 대한 .OnApplyWindowInsetsListener

ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
    val imeVisible = insets.isVisible(Type.ime())
}

하드 코드를 만들지 마세요.가장 좋은 방법은 KeyBord Show를 사용하여 텍스트 편집에 초점을 맞추는 동안 보기 크기를 조정하는 것입니다.아래 코드를 사용하여 활동의 크기 조정 속성을 매니페스트 파일에 추가할 수 있습니다.

android:windowSoftInputMode="adjustResize"

제 답변은 기본적으로 카치의 답변과 동일하지만, 제 앱 전체에서 사용되는 방식을 정리하기 위해 멋진 도우미 클래스로 포장했습니다.

import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

/**
 * Detects Keyboard Status changes and fires events only once for each change
 */
public class KeyboardStatusDetector {
    KeyboardVisibilityListener visibilityListener;

    boolean keyboardVisible = false;

    public void registerFragment(Fragment f) {
        registerView(f.getView());
    }

    public void registerActivity(Activity a) {
        registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
    }

    public KeyboardStatusDetector registerView(final View v) {
        v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                v.getWindowVisibleDisplayFrame(r);

                int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
                    /** Check this variable to debounce layout events */
                    if(!keyboardVisible) {
                        keyboardVisible = true;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
                    }
                } else {
                    if(keyboardVisible) {
                        keyboardVisible = false;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
                    }
                }
            }
        });

        return this;
    }

    public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
        visibilityListener = listener;
        return this;
    }

    public static interface KeyboardVisibilityListener {
        public void onVisibilityChanged(boolean keyboardVisible);
    }
}

이 기능을 사용하여 다음과 같이 앱 전체에서 키보드 변경을 감지할 수 있습니다.

    new KeyboardStatusDetector()
            .registerFragment(fragment)  //register to a fragment 
            .registerActivity(activity)  //or register to an activity
            .registerView(view)          //or register to a view
            .setVisibilityListener(new KeyboardVisibilityListener() {
                @Override
                public void onVisibilityChanged(boolean keyboardVisible) {
                    if(keyboardVisible) {
                       //Do stuff for keyboard visible
                    }else {
                       //Do stuff for keyboard hidden
                    }
                }
            });

참고: "등록" 통화 중 하나만 사용합니다.그들은 모두 똑같이 일하고 단지 편의를 위해 거기에 있습니다.

저는 이 방법이 당신이 키보드가 보이는지 아닌지 알아내는 데 도움이 될 것이라고 생각합니다.

 public Boolean isSoftKeyBoardVisible(){
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
        return true;
    } else {
        Log.d(TAG,"Software Keyboard was not shown");
        return false;
    }

}

당신은 이것을 시도할 수 있고, 나를 위해 잘 일할 수 있습니다.

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

if (imm.isAcceptingText()) {
    //Software Keyboard was shown..
} else {
    //Software Keyboard was not shown..
}

보기 페이지에서 조각의 방향을 변경할 때 키보드 상태를 유지하는 데 어려움이 있었습니다.이유는 잘 모르겠지만, 그냥 어색하고 일반적인 활동과 다르게 행동합니다.

이 이경키드상유태려면먼지합추저니다를 추가해야 .android:windowSoftInputMode = "stateUnchanged"의 신에게에.AndroidManifest.xml하지만 여러분은 이것이 모든 문제를 실제로 해결하지는 않는다는 것을 아실 것입니다. 만약 키보드가 방향이 바뀌기 전에 열렸다면 저를 위해 열리지 않았습니다.다른 모든 경우에서, 그 행동은 옳은 것처럼 보였습니다.

그런 다음 여기서 언급한 솔루션 중 하나를 구현해야 합니다.내가 찾은 가장 깨끗한 것은 George Maisuradze의 --hideSoftInputFromWindow에서 부울 콜백 사용:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);

는 이 의 이값내단저습다에 했습니다.onSaveInstanceState했습니다.onCreate그리고 키보드를 강제로 보여주었습니다.onCreateView 그것이 있가가다면의 .true(프래그먼트 파괴 전에 실제로 숨기기 전에 키보드가 보이면 true를 반환합니다.)

여기 제 해결책이 있습니다. 효과가 있습니다.픽셀 크기를 찾는 대신 콘텐츠 보기의 높이가 변경되었는지 확인하십시오.

// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        private int oldHeight;

        @Override
        public void onGlobalLayout() {
            int newHeight = commentsContent.getMeasuredHeight();
            if (newHeight < oldHeight) {
                // Check for the keyboard showing in case the height difference
                // is a result of orientation change
                if (isSoftKeyboardShowing(CommentsActivity.this)) {
                    // Keyboard is showing so scroll to the latest comment
                    scrollToLatestComment();
                }
            }
            oldHeight = newHeight;
        }

    });


public static boolean isSoftKeyboardShowing(Activity activity) {
    InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    return inputMethodManager.isActive();
}

이것을 알 수 있는 직접적인 방법이 있습니다.또한 레이아웃을 변경할 필요가 없습니다.
따라서 몰입형 전체 화면 모드에서도 작동합니다.

비결은 소프트 키보드를 숨기거나 표시하고 해당 시도의 결과를 캡처하는 것입니다.
당황할 필요 없습니다. 키보드를 표시하거나 숨기지 않습니다.우리는 단지 국가를 요청할 뿐입니다.

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

구현 사례는 https://stackoverflow.com/a/27567074/2525452 에서 확인할 수 있습니다.

이 솔루션은 키보드를 다시 열 수 있지만 작동합니다.

InputMethodManager inputManager = ( (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE) );

private boolean isKeyboardShowing() {

    boolean isKeyboardShowing = inputManager.hideSoftInputFromWindow(irrelevantView.getWindowToken(), 0);
    if (isKeyboardShowing) {
        inputManager.showSoftInput(this.getCurrentFocus(), 0);
    }
    return isKeyboardShowing;
}

해상도가 다른 몇 가지 문제를 이해한 후, 저는 상대적인 크기를 사용하기로 결정했습니다.눈에 보이는 상태와 숨겨진 상태의 차이는 약 30%입니다.그래서 저는 128 PX를 0.3으로 교체하기로 했습니다.

그리고 변경 사항을 알리기 위해 이 클래스 청취자를 추가했습니다.

여기 제 버전이 있습니다.

import android.app.*;
import android.graphics.*;
import android.view.*;

public class SoftKeyboardState {
  public static final int HIDDEN = 0, VISIBLE = 1;
  private OnKeyboardStateChangedListener listener;
  private View decorView;

  public SoftKeyboardState(Activity activity) {
    this.decorView = activity.findViewById(android.R.id.content);
    initKeyboardListener();
  }

  private void initKeyboardListener() {
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(
      new ViewTreeObserver.OnGlobalLayoutListener(){
        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) && (lastVisibleDecorViewHeight / visibleDecorViewHeight >= 0.3f)) {
              // visible
              if (listener != null)listener.onKeyboardStateChanged(VISIBLE);
            } else if ((lastVisibleDecorViewHeight < visibleDecorViewHeight) && (visibleDecorViewHeight / lastVisibleDecorViewHeight >= 0.3f)) {
              // hidden
              if (listener != null)listener.onKeyboardStateChanged(HIDDEN);
            }
          }
          lastVisibleDecorViewHeight = visibleDecorViewHeight;
        }
      });
  }

  public void setOnKeyboardStateChangedListener(OnKeyboardStateChangedListener listener) {
    this.listener = listener;
  }

  public interface OnKeyboardStateChangedListener {
    public void onKeyboardStateChanged(int state);
  }
}

여기서 99%의 솔루션은 IME WINDOW SIZE 확률에 기반을 두고 있으며 각 솔루션은 해시...가치가 있습니다!

이유:

  1. 오버레이 - 사용자 앱 또는 시스템 앱에서 제공
  2. IME에는 최소 크기가 없으며 창 크기의 100%를 차지할 수 있으며 개발자 구현의 상상력만큼 얇을 수 있습니다 :)
  3. 모달 창 / 다중 창
  4. 그리고 많은 사람들이 IPC에 대한 지식이 없는 것을 좋아합니다(예: 외부 창 또는 내용 탐지).

그래서 IME라고 추측하는 것은 항상 틀립니다. 확실하게 추측하지 마세요!!!

@kevin-du는 IME 높이에 대한 쿼리 IMM으로 현재 가장 좋은 솔루션 라이트이지만, 이 방법은 숨겨진 API이므로 잘못된 개발 사용으로 인해 잘못된 "잘못된 부정적 결과"를 얻는 데 위험할 수 있습니다.

언급URL : https://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android

반응형