매우 간단한 작업을 수행해야합니다. 소프트웨어 키보드가 표시되어 있는지 확인하십시오. 이것은 안드로이드에서 가능합니까?
매우 간단한 작업을 수행해야합니다. 소프트웨어 키보드가 표시되어 있는지 확인하십시오. 이것은 안드로이드에서 가능합니까?
답변:
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
}
...
}
((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)
android.R.id.content
)를 사용 하여이 작업을 시도하면 System
응용 프로그램이 아닌 높이가 변경되는 엔티티 라고 자신있게 말할 수 있습니다 . Android 팀이 휴식을 취하고 SoftKeyboard 입력에 대해 최소한 기본 사항을 알려주는 것이 훨씬 안전합니다.
heightDiff
항상 작업 표시 줄의 높이를 포함 할 것이다. 높이가 일부 상수보다 크지 만 Nexus 4와 같은 xxhdpi 장치에는 100 픽셀이면 충분하지 않은 경우 테스트를 통해 무시 된 새로운 답변 에서이 해킹 된 작업을 실제로 사용하려면 해당 값을 DP로 변환하십시오 주위에.
희망적으로 이것은 누군가를 도와줍니다.
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
}
}
});
TwoDScrollerView
과 유사한 사용자 정의에서 키보드 상태를 감지하려고했습니다 . 자식은 단순하지 않지만 사용자 정의 레이아웃 (확장자 ) 이었지만 설정에도 불구하고 권장 솔루션을 사용하여 키보드를 감지 할 수 없었습니다 . 감사! ImageView
RelativeLayout
android:windowSoftInputMode="adjustResize"
ActionBar
하고 ActionBarSherlock
. 고마워요! 그건 그렇고, 방법이 있습니다 r.height()
:)
heightDiff > root.getRootView().getHeight() / 4
고해상도 장치와 함께 사용하기에 좋은 가치입니다. 100px는 짧습니다. 1080x1920 해상도, 1920-(996-75)의 Nexus 5에서>? 100 = 999 1920-(1776-75)>? 100 = 219 // 480x800 해상도의 은하 s2에서 키보드가 작동 중-800-(800-38)>? 100 = 38800-(410-38)>? 100 = 428 // 키보드가 작동하므로 마법 번호 100px로 충분하지 않습니다.
그것은 컴퓨터의 관점에서 영원히 있었지만이 질문은 여전히 믿을 수 없을 정도로 관련이 있습니다!
그래서 위의 답변을 취하여 조금 조합하고 개선했습니다 ...
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
getLastKeyboardHeightInPx()
해당 행의 높이가 포함되지 않으므로 키보드 자체의 일부 가 아닙니다. 당신도 그것을 고려하는 방법을 알고 있습니까?
고밀도 장치에서 소프트 키보드의 가시성을 잘못 감지하지 않도록하기위한 몇 가지 개선 사항 :
높이 차이의 임계 값은 128 픽셀이 아니라 128dp 로 정의해야합니다 .
참조 지표 및 그리드에 대한 구글 설계 문서 , 48 DP는 터치 개체에 대한 편안 크기이며, 32 DP는 버튼을 최소이다. 일반 소프트 키보드에는 4 행의 키 버튼이 포함되어야하므로 최소 키보드 높이는 32dp * 4 = 128dp 이어야합니다. 즉, 임계 값 크기는 장치 밀도를 곱하여 픽셀로 전송해야합니다. xxxhdpi 장치 (밀도 4)의 경우 소프트 키보드 높이 임계 값은 128 * 4 = 512 픽셀이어야합니다.
루트 뷰와 해당 가시 영역의 높이 차이 :
루트 뷰 높이-상태 표시 줄 높이-보이는 프레임 높이 = 루트 뷰 하단-보이는 프레임 하단 (상태 표시 줄 높이는 루트 뷰 표시 프레임의 상단과 동일하므로)
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
아이디어는 키보드를 숨기고 동시에 소프트 입력 상태를 확인해야하는 경우 다음 해결 방법을 사용하는 것입니다.
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
이 메소드는 숨기 전에 키보드가 표시되면 true를 리턴합니다.
@Reuben_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
}
}
});
활동의 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
) 에서만 작동합니다 . 의 BottomNavigationView
하위 항목이 LinearLayout
있고 키보드가 표시되면 숨겨야 한다고 가정 해보십시오 .
> 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;
}
}
아이디어는 키보드가 표시 될 때 시스템 삽입 .bottom
값 이 매우 큰 값으로 변경된다는 것입니다 .
이를 위해 숨겨진 방법이 있습니다 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()
}
}
이러한 솔루션 중 어느 것도 Lollipop에 그대로 작동하지 않습니다. 롤리팝 activityRootView.getRootView().getHeight()
에서 버튼 막대의 높이는 포함하지만 뷰 측정에는 포함되지 않습니다. Lollipop과 함께 작동하기 위해 위의 최고 / 간단한 솔루션을 조정했습니다.
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와 ur 앱 콘텐츠의 차이를 얻은 다음 그 차이의 백분율을 확인하십시오. 내가 얻은 통계에서 대부분의 탐색 표시 줄 (크기, 해상도 등에 관계없이)은 화면의 3 %에서 5 % 사이입니다. 키보드가 열린 것처럼 화면의 47 % ~ 55 %를 차지했습니다.
결론적으로 내 솔루션은 diff가 10 % 이상인지 확인하고 키보드가 열린 것으로 가정합니다.
Reuban의 답변 중 약간의 변형을 사용하여 특정 상황, 특히 고해상도 장치에서 더 도움이되는 것으로 나타났습니다.
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
}
}
});
R.id.activityRoot
사용할 수 있습니다 android.R.id.content
.
그것은 컴퓨터와 관련하여 영원히 존재했지만이 질문은 여전히 믿을 수 없을 정도로 관련이 있습니다! 그래서 위의 답변을 취하여 조금 조합하고 개선했습니다 ...
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 ... \\
}
}
});
내 대답은 기본적으로 Kachi의 대답과 동일하지만 앱 전체에서 사용되는 방식을 정리하기 위해 멋진 도우미 클래스로 래핑했습니다.
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
}
}
});
참고 : "등록"호출 중 하나만 사용하십시오. 그들은 모두 똑같이 작동하며 편의를 위해서만 있습니다.
당신은 이것을 시도 할 수 있습니다, 나를 위해 위대한 일 :
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);
이 값을 Fragment의 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
에서 구현을 찾을 수 있습니다.
이 방법을 사용하면 키 보드가 표시되는지 여부를 알 수 있습니다.
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;
}
}
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
반투명 상태 표시 줄 모드를 설정하면 Reuben Scratton의 새 답변 (HeightDiff 계산 )이 작동하지 않습니다.
반투명 상태 표시 줄을 사용하는 경우 activityRootView.getHeight()
소프트 키보드가 보이는 날씨를 변경하지 않습니다. 항상 활동 높이와 상태 표시 줄을 반환합니다.
예를 들어 Nexus 4, Android 5.0.1 android:windowTranslucentStatus
은 true로 설정 하면 심지어 1ime을 열었을 수도 있습니다. android:windowTranslucentStatus
false로 설정 하면 높이를 올바르게 반환하고 ime가 보이지 않으면 1134를 반환합니다 (상태 표시 줄을 포함하지 않음). ime을 닫으면 5xx를 반환합니다 (ime의 높이에 따라 다름)
나는 이것이 버그인지 날씨를 모른다. 나는 4.4.4와 5.0.1에서 시도했지만 결과는 동일하다.
따라서 지금까지 두 번째로 가장 합의 된 답변 인 Kachi의 솔루션은 ime 높이를 가장 안정시키는 가장 안전한 방법이 될 것입니다. 사본은 다음과 같습니다.
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 > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});
방법 LayoutListener이 필요하지 않습니다
필자의 경우 Fragment를 교체하기 전에 키보드 상태를 저장하고 싶습니다. hideSoftInputFromWindow from 메소드를 호출하여 onSaveInstanceState
키보드를 닫고 키보드의 표시 여부를 반환합니다.
이 방법은 간단하지만 키보드 상태가 변경 될 수 있습니다.
나는 이것이 오래된 게시물이라는 것을 알고 있지만 이것이 내가 아는 가장 간단한 접근법이며 내 테스트 장치는 Nexus 5라고 생각합니다. 다른 장치에서는 시도하지 않았습니다. 내 코드가 좋지 않다면 다른 사람들이 접근 방식을 공유하기를 바랍니다. :)
public static boolean isKeyboardShown(Context context, View view) {
if (context == null || view == null) {
return false;
}
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
imm.hideSoftInputFromWindow는 부울을 반환합니다.
감사,
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
위의 기능은 키보드가 보이는지 확인하는 데 사용합니다. 그렇다면 닫습니다.
아래는 필요한 두 가지 방법을 보여줍니다.
먼저 onCreate에서 실행 가능한 창 높이를 정의하십시오.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// add to onCreate method
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
sheight= rectgle.bottom;
//
}
그런 다음 해당 인스턴스에서 Window 높이를 가져 오는 부울 메소드를 추가하십시오. 원본과 일치하지 않으면 (길을 따라 변경하지 않는다고 가정) 키보드가 열려 있습니다.
public boolean keyopen()
{
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int curheight= rectgle.bottom;
if (curheight!=sheight)
{
return true;
}
else
{
return false;
}
}
프로 츠!
키보드가 숨겨져 있는지 여부를 얼마나 정확하게 결정할 수 있는지 알고 있습니다.
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public int getNavigationBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public boolean isKeyboardHidden() {
int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
- getSupportActionBar().getHeight();
return delta <= 0;
}
이것은 태블릿에서 작동합니다. 탐색 표시 줄이 가로로 표시되는 경우