Android에서 소프트웨어 키보드의 가시성을 확인하는 방법은 무엇입니까? 수행해야합니다. 소프트웨어 키보드가 표시되어 있는지 확인하십시오. 이것은

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



답변

NEW ANSWER 추가 2012 년 1 월 25 일

아래 답변을 작성한 후 누군가가 ViewTreeObserver 와 친구들, 버전 1 이후 SDK에 숨어있는 API가 있음을 알려주었습니다 .

사용자 정의 레이아웃 유형이 필요하지 않고 훨씬 간단한 솔루션은 활동의 루트보기에 알려진 ID를 부여하는 것입니다 @+id/activityRoot.

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 Manifest 에서이 플래그를 설정해야합니다. 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
    }

    ...
}

답변

희망적으로 이것은 누군가를 도와줍니다.

Reuben Scratton이 제공 한 새로운 답변은 훌륭하고 효율적이지만 windowSoftInputMode를 adjustResize로 설정 한 경우에만 작동합니다. 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.bottom - r.top);
    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);
        }
    });
}

나를 위해 작동 🙂

참고 :
당신이 알 경우 DefaultKeyboardDP이 값으로 장치 플레이에 적합하고 값을해야하는지 알고 모두에 대한 소감을 게시하지 않습니다 … 결국 우리는 모든 장치에 맞게 올바른 값을 얻을 것이다!

자세한 내용은 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 로 정의해야합니다 .
    참조 지표 및 그리드에 대한 구글 설계 문서 , 48 DP는 터치 개체에 대한 편안 크기이며, 32 DP는 버튼을 최소이다. 일반 소프트 키보드에는 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;
    }

답변

나는 이것을 알아 내기 위해 약간의 시간을 사용했다 … 나는 그것을 CastExceptions를 실행했지만 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>

이렇게하면 캐스트 문제가 발생하지 않습니다.

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


답변

WifiKeyboard와 같은 일부 키보드의 높이는 0이므로 요소의 높이를 확인하는 것은 신뢰할 수 없습니다.

대신 showSoftInput () 및 hideSoftInput ()의 콜백 결과를 사용하여 키보드 상태를 확인할 수 있습니다. 자세한 내용 및 예제 코드

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