Android 활동의 소프트 키보드 열기 및 닫기 리스너


136

나는 Activity5 EditText초가 있는 곳이 있습니다 . 사용자가 첫 번째를 클릭 EditText하면 소프트 키보드가 열리고 일부 값을 입력합니다. 소프트 키보드가 열릴 때와 사용자가 첫 번째를 클릭 할 때와 소프트 키보드가 뒤로 버튼 누름 에서 동일하게 닫힐 때 다른 View가시성 을 설정하고 싶습니다 . 그런 다음 다른 가시성을 가시 로 설정하고 싶습니다 .GoneEditTextEditTextView

EditTextAndroid 에서 첫 번째 클릭으로 소프트 키보드가 열릴 때 리스너 또는 콜백 또는 해킹이 있습니까?


1
아니요. 그러한 청취자는 없습니다. 당신이하려는 것을 달성하기위한 해킹 이 있습니다 . 가능한 접근 방법은 다음과 같습니다 . Android에서 포인터 이벤트를 보내는 방법 .
Vikram

@Vikram 내가 찾고 있지 않습니다trying to detect the virtual keyboard height in Android.
N Sharma

알아. 코드를 살펴보면 높이가 어떻게 결정되는지 알 수 있습니다. 포인터 이벤트가 전송되고 있습니다.-> 두 경우 => 1. 키보드가 열려있는 경우 => & 포인터 XY위치가 키보드를 넘어서거나 넘어가는 경우 => SecurityException=> 감소 Y하고 예외가 발생하지 않을 때까지 => 다시 시도하십시오 => 현재 Y값은 키보드 높이입니다. 2. 키보드가 열려 있지 않으면 => no SecurityException.
Vikram

시나리오에 어떻게 적용됩니까? 화면 높이의 2/3라고 가정하면 포인터 이벤트를 보냅니다. a SecurityException를 던지면 => 키보드가 열립니다. 그렇지 않으면 키보드가 닫힙니다.
Vikram

@Vikram 나는 이것을 EditText다른 사람 이 아닌 처음으로 원한다 EditText. 이것을 어떻게 구별 할 수 있습니까?
N Sharma

답변:


91

이것은 매니페스트에서 android:windowSoftInputMode활동이 설정된 경우에만 작동합니다 adjustResize. 레이아웃 리스너를 사용하여 키보드로 활동의 루트 레이아웃 크기를 조정할 수 있습니다.

활동에 다음 기본 클래스와 같은 것을 사용합니다.

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

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

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

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

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

    private boolean keyboardListenersAttached = false;
    private ViewGroup rootLayout;

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

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

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

        keyboardListenersAttached = true;
    }

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

        if (keyboardListenersAttached) {
            rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
        }
    }
}

다음 활동 예는 키보드를 표시 할 때보기를 숨기고 키보드를 숨길 때 다시 표시하기 위해이를 사용합니다.

xml 레이아웃 :

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

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

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

        <!-- omitted for brevity -->

    </ScrollView>

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

        <!-- omitted for brevity -->

    </LinearLayout>

</LinearLayout>

그리고 활동 :

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

        attachKeyboardListeners();
    }

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

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

4
+1 예 내 문제에 대한 완벽한 솔루션입니다.
N Sharma

18
안녕하세요, Window.ID_ANDROID_CONTENT에서 getTop ()을 사용했습니다. 최고를 얻을 수 없습니다. 항상 0이며 getHeight ()를 대신 사용하는 것처럼 작동합니다.
Daniele Segato

1
어디서 오셨어요 rootLayout = (ViewGroup) findViewById(R.id.rootLayout);?
CommonSenseCode

1
어떤 이유로 든 나를 위해 일하지 않으면 항상 열려 있거나 닫을 때 onShowKeyboard를 호출합니다. findViewById (android.R.id.content)를 사용하고 있는데, 이것이 문제입니까?
McSullivan D' Ander

2
@tsig +100 솔루션은 특정 화면에 따라 다릅니다. 태블릿 및 hdpi 전화에서 실패했습니다. 장치 높이의 10 %로 수정을 사용했습니다. 즉,보기 높이가 screenHeight-10 %보다 낮 으면 키보드가 열린 것입니다. 그렇지 않으면 키보드가 닫힙니다. onGlobalLayout의 내 contentViewTop은 다음과 같습니다. contentViewTop = (getWindow (). getDecorView (). getBottom () / 10)
ilker

94

멋진 KeyboardVisibilityEvent 라이브러리 가 포함 된 케이크 조각

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

Yasuhiro SHIMIZU의 크레딧


키보드의 정적 높이가없고이 라이브러리의 높이가 100dp로 설정되어 있기 때문에 작동하지 않습니다.
milosmns

@milosmns 임계 값 높이 100dp는 키보드 감지에 사용됩니다. 어떤 가정은 실제 키보드의 높이에 대해 이루어지지 않습니다
니노 반 Hooff을

11
여전히 하드 코딩되어 있습니다. 멀티 윈도우? 삼성 분할보기? 사진 모드의 사진? 또한 100dp 이하의 최소 한 줄 키보드가 있습니다. 여기에은 총알이 없습니다 ...
milosmns

1
이 문제에 대한 모든 정보가 없으므로 구현하기가 가장 쉬운 것 같습니다. 실제로 작업하려는 코드로 돌아가십시오. :)
Machine Tribe

1
이것은 모든 장치에서 완전히 신뢰할 수있는 최고의 답변입니다.
Pelanes

69

Vikram이 의견에서 지적했듯이 소프트 키보드가 표시되는지 또는 사라 졌는지 감지하는 것은 일부 추악한 해킹에서만 가능합니다.

편집 텍스트에 포커스 리스너설정하는 것으로 충분할 수 있습니다. .

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

27
edittext를 클릭하면 setOnFocusChangeListener리스너가 호출되고 다시 누르면 키보드가 닫히고 다른 뷰를 클릭하지 않았습니다. 이제 다시 포커스가있는 동일한 edittext를 클릭하면 어떻게 될까요?
N Sharma

3
@ Williams 나는 확실하지 않지만, 나는 그것이 onFocusChange()호출되지 않을 것이라고 생각합니다 .
CommonGuy

1
이것은 내 질문이 아니다. 내 질문을 다시 읽으십시오-5 개의 EditText가있는 활동이 있습니다. 사용자가 첫 번째 EditText를 클릭하면 소프트 키보드가 열려 값을 입력합니다. 사용자가 첫 번째 EditText를 클릭 할 때 소프트 키보드가 열리고 후면 키보드의 동일한 EditText에서 소프트 키보드가 닫히면 다른 View 가시성을 가시로 설정하고 싶습니다. Android에서 첫 번째 EditText를 클릭하면 소프트 키보드가 열릴 때 리스너 또는 콜백 또는 해킹이 있습니까?
N Sharma

4
내가 이해할 수없는 것조차 다른 것을 말하고 있기 때문에 사람들은이 대답을 보지 않습니다.
N Sharma

2
어쨌든, 그것은 나를 위해 작동하지 않습니다 ... 소프트 키보드가 숨겨져있을 때 EditText에 포커스 변경이 발생하지 않았습니다 ... 그래서이 리스너에게 알릴 수 없습니다.
Licat Julius

50

활동의 경우 :

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

                activityRootView.getWindowVisibleDisplayFrame(r);

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

조각의 경우 :

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

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

                }
            }
        });

3
활동에 사용했지만보기와 비교하는 대신 화면 크기와 비교했습니다. 잘 작동
Roee

heightDiff를 픽셀이 아닌 dp의 높이와 비교하는 것이 좋습니다. 크게 다를 수 있습니다.
레오 드로이드 코더

이것이 android:windowSoftInputMode="adjustResize"in 매니페스트 가 필요합니까 ?
LiuWenbin_NO.

android : windowSoftInputMode = "adjustResize"android : configChanges = "orientation | keyboard | keyboardHidden"
M Singh Karnawat

그것은 여전히 ​​효과가 있지만 질문이 있습니다. 많은 자원이 필요합니까?
Licat Julius

32

야프 답변은 AppCompatActivity에서 작동하지 않습니다. 대신 상태 표시 줄 및 탐색 표시 줄의 높이를 가져 와서 앱의 창 크기와 비교하십시오.

이렇게 :

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

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

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

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

        if (keyboardHeight <= 0) {
            onHideKeyboard();
        } else {
            onShowKeyboard(keyboardHeight);
        }
    }
};

분할 화면 모드에서 중단되는 경우를 제외하고는 꽤 잘 작동하는 것 같습니다. 그렇지 않으면 훌륭합니다.
MCLLC

14

당신은 그것을 시도 할 수 있습니다 :

private void initKeyBoardListener() {
    // Минимальное значение клавиатуры. 
    // Threshold for minimal keyboard height.
    final int MIN_KEYBOARD_HEIGHT_PX = 150;
    // Окно верхнего уровня view. 
    // Top-level window decor view.
    final View decorView = getWindow().getDecorView();
    // Регистрируем глобальный слушатель. Register global layout listener.
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        // Видимый прямоугольник внутри окна. 
        // Retrieve visible rectangle inside window.
        private final Rect windowVisibleDisplayFrame = new Rect();
        private int lastVisibleDecorViewHeight;

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

            if (lastVisibleDecorViewHeight != 0) {
                if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) {
                    Log.d("Pasha", "SHOW");
                } else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) {
                    Log.d("Pasha", "HIDE");
                }
            }
            // Сохраняем текущую высоту view до следующего вызова.
            // Save current decor view height for the next call.
            lastVisibleDecorViewHeight = visibleDecorViewHeight;
        }
    });
}

스파 시보, 돌빅! :)
AlexS

4

Rx 확장 기능 (Kotlin)을 사용할 수 있습니다.

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

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

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

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

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

    val visibleDisplayFrame = Rect()

    val viewTreeObserver = window.decorView.viewTreeObserver

    val onDrawListener = ViewTreeObserver.OnDrawListener {

        window.decorView.getWindowVisibleDisplayFrame(visibleDisplayFrame)

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

        val keyboardOpen = keyboardHeight >= approximateKeyboardHeight

        val hasChanged = isKeyboardOpen xor keyboardOpen

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

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

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

    return notifier
            .doOnDispose {
                viewTreeObserver.removeOnDrawListener(onDrawListener)
                lifecycle.removeObserver(lifeCycleObserver)
            }
            .onTerminateDetach()
            .hide()
}

예:

(context as AppCompatActivity)
                    .keyboardVisibilityChanges()
                    .subscribeBy { isKeyboardOpen ->
                        // your logic
                    }

나를 위해 작동하지 않습니다. 방법을 찾을 수 없습니다 dip()getScreenHeight()
마르신 KUNERT

@MarcinKunert 그것은 픽셀을 dp로 변환하고 화면 높이를 얻는 데 도움이되는 확장 기능 일뿐입니다. 원하는 경우 이러한 기능의 예를들 수 있습니다.
Vlad

GenericLifecycleObserver는 더 이상 사용되지 않습니까? 어떤 해결책?
Zainal Fahrudin

4

아래 코드는 나를 위해 일하고 있습니다.

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

2

가능하면 EditText를 확장하고 'onKeyPreIme'메소드를 대체하십시오.

@Override
public void setOnEditorActionListener(final OnEditorActionListener listener) {
    mEditorListener = listener; //keep it for later usage
    super.setOnEditorActionListener(listener);
}

@Override
public boolean onKeyPreIme(final int keyCode, final KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        if (mEditorListener != null) {
            //you can define and use custom listener,
            //OR define custom R.id.<imeId>
            //OR check event.keyCode in listener impl
            //* I used editor action because of ButterKnife @
            mEditorListener.onEditorAction(this, android.R.id.closeButton, event);
        }
    }
    return super.onKeyPreIme(keyCode, event);
}

어떻게 확장 할 수 있습니까?

  1. onFocus 청취 구현 및 'onKeyboardShown'선언
  2. 'onKeyboardHidden'을 선언하십시오.

이전에 언급 한 것처럼 화면 높이를 다시 계산하는 것이 100 % 성공적이지 않다고 생각합니다. 분명히, 'onKeyPreIme'의 재정의는 '소프트 키보드 숨기기 프로그래밍'방법에서 호출되지 않지만 어디에서든 수행하는 경우 'onKeyboardHidden'논리를 수행하고 포괄적 인 솔루션을 작성하지 않아야합니다.


1
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mainactivity);
    attachKeyboardListeners();
    ....
    yourEditText1.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                yourEditText2.setVisibility(View.GONE);
                yourEditText3.setVisibility(View.GONE);
                yourEditText4.setVisibility(View.GONE);
                yourEditText5.setVisibility(View.GONE);
            } else {
                yourEditText2.setVisibility(View.VISIBLE);
                yourEditText3.setVisibility(View.VISIBLE);
                yourEditText4.setVisibility(View.VISIBLE);
                yourEditText5.setVisibility(VISIBLE);
            }
       }
    });
    }
}

편집 텍스트를 클릭 한 다음 setOnFocusChangeListener 리스너가 호출되고 다시 누르면 키보드가 닫히고 다른 뷰를 클릭하지 않았습니다. 이제 다시 포커스가있는 동일한 edittext를 클릭하면 어떻게 될까요?
N Sharma

이것은 내 질문이 아니다. 내 질문을 다시 읽으십시오-5 개의 EditText가있는 활동이 있습니다. 사용자가 첫 번째 EditText를 클릭하면 소프트 키보드가 열려 값을 입력합니다. 사용자가 첫 번째 EditText를 클릭 할 때 소프트 키보드가 열릴 때와 다시 누르면 동일한 EditText에서 소프트 키보드가 닫히면 다른 View 가시성을 가시로 설정하고 싶습니다. Android에서 첫 번째 EditText를 클릭하면 소프트 키보드가 열릴 때 리스너 또는 콜백 또는 해킹이 있습니까?
N Sharma

1
뒤로 밀면 시간 onfocus청취자가 전화를하지 않는 키보드 가 사라집니다
N Sharma

1

이 수업을 이용하세요

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

public class SoftKeyboard implements View.OnFocusChangeListener
{
private static final int CLEAR_FOCUS = 0;

private ViewGroup layout;
private int layoutBottom;
private InputMethodManager im;
private int[] coords;
private boolean isKeyboardShow;
private SoftKeyboardChangesThread softKeyboardThread;
private List<EditText> editTextList;

private View tempView; // reference to a focused EditText

public SoftKeyboard(ViewGroup layout, InputMethodManager im)
{
    this.layout = layout;
    keyboardHideByDefault();
    initEditTexts(layout);
    this.im = im;
    this.coords = new int[2];
    this.isKeyboardShow = false;
    this.softKeyboardThread = new SoftKeyboardChangesThread();
    this.softKeyboardThread.start();
}

public void openSoftKeyboard()
{
    if(!isKeyboardShow)
    {
        layoutBottom = getLayoutCoordinates();
        im.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);
        softKeyboardThread.keyboardOpened();
        isKeyboardShow = true;
    }
}

public void closeSoftKeyboard()
{
    if(isKeyboardShow)
    {
        im.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
        isKeyboardShow = false;
    }
}

public void setSoftKeyboardCallback(SoftKeyboardChanged mCallback)
{
    softKeyboardThread.setCallback(mCallback);
}

public void unRegisterSoftKeyboardCallback()
{
    softKeyboardThread.stopThread();
}

public interface SoftKeyboardChanged 
{
    public void onSoftKeyboardHide();
    public void onSoftKeyboardShow();   
}

private int getLayoutCoordinates()
{
    layout.getLocationOnScreen(coords);
    return coords[1] + layout.getHeight();
}

private void keyboardHideByDefault()
{
    layout.setFocusable(true);
    layout.setFocusableInTouchMode(true);
}

/*
 * InitEditTexts now handles EditTexts in nested views
 * Thanks to Francesco Verheye (verheye.francesco@gmail.com)
 */
private void initEditTexts(ViewGroup viewgroup) 
{
    if(editTextList == null)
        editTextList = new ArrayList<EditText>();

    int childCount = viewgroup.getChildCount();
    for(int i=0; i<= childCount-1;i++) 
    {
        View v = viewgroup.getChildAt(i);

        if(v instanceof ViewGroup) 
        {
            initEditTexts((ViewGroup) v);
        }

        if(v instanceof EditText) 
        {
            EditText editText = (EditText) v;
            editText.setOnFocusChangeListener(this);
            editText.setCursorVisible(true);
            editTextList.add(editText);
        }
    }
}

/*
 * OnFocusChange does update tempView correctly now when keyboard is still shown
 * Thanks to Israel Dominguez (dominguez.israel@gmail.com)
 */
@Override
public void onFocusChange(View v, boolean hasFocus) 
{
    if(hasFocus) 
    {
        tempView = v;
        if(!isKeyboardShow) 
        {
            layoutBottom = getLayoutCoordinates();
            softKeyboardThread.keyboardOpened();
            isKeyboardShow = true;
        }
    }
}

// This handler will clear focus of selected EditText
private final Handler mHandler = new Handler()
{
    @Override
    public void handleMessage(Message m)
    {
        switch(m.what)
        {
        case CLEAR_FOCUS:
            if(tempView != null)
            {
                tempView.clearFocus();
                tempView = null;
            }
            break;
        }
    }
};

private class SoftKeyboardChangesThread extends Thread
{
    private AtomicBoolean started;
    private SoftKeyboardChanged mCallback;

    public SoftKeyboardChangesThread()
    {
        started = new AtomicBoolean(true);
    }

    public void setCallback(SoftKeyboardChanged mCallback)
    {
        this.mCallback = mCallback;
    }

    @Override
    public void run()
    {
        while(started.get())
        {
            // Wait until keyboard is requested to open
            synchronized(this)
            {
                try 
                {
                    wait();
                } catch (InterruptedException e) 
                {
                    e.printStackTrace();
                }
            }

            int currentBottomLocation = getLayoutCoordinates();

            // There is some lag between open soft-keyboard function and when it really appears.
            while(currentBottomLocation == layoutBottom && started.get())
            {
                currentBottomLocation = getLayoutCoordinates();
            }

            if(started.get())
                mCallback.onSoftKeyboardShow();

            // When keyboard is opened from EditText, initial bottom location is greater than layoutBottom
            // and at some moment equals layoutBottom.
            // That broke the previous logic, so I added this new loop to handle this.
            while(currentBottomLocation >= layoutBottom && started.get())
            {
                currentBottomLocation = getLayoutCoordinates();
            }

            // Now Keyboard is shown, keep checking layout dimensions until keyboard is gone
            while(currentBottomLocation != layoutBottom && started.get())
            {
                                    synchronized(this)
                {
                    try 
                    {
                        wait(500);
                    } catch (InterruptedException e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                currentBottomLocation = getLayoutCoordinates();
            }

            if(started.get())
                mCallback.onSoftKeyboardHide();

            // if keyboard has been opened clicking and EditText.
            if(isKeyboardShow && started.get())
                isKeyboardShow = false;

            // if an EditText is focused, remove its focus (on UI thread)
            if(started.get())
                mHandler.obtainMessage(CLEAR_FOCUS).sendToTarget();
        }   
    }

    public void keyboardOpened()
    {
        synchronized(this)
        {
            notify();
        }
    }

    public void stopThread()
    {
        synchronized(this)
        {
            started.set(false);
            notify();
        }
    }

}
}

에서가 Android Manifest, android:windowSoftInputMode="adjustResize"필요합니다.

/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root
InputMethodManager im = (InputMethodManager)getSystemService(Service.INPUT_METHOD_SERVICE);

/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged() {

@Override
public void onSoftKeyboardHide()  {
    // Code here
}

@Override
public void onSoftKeyboardShow() {
    // Code here
}   
});

/*
Open or close the soft keyboard easily
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();

/* Prevent memory leaks:*/
@Override
public void onDestroy() {
    super.onDestroy();
    softKeyboard.unRegisterSoftKeyboardCallback();
}

PS- 완전히 여기 에서 가져 왔습니다 .


1

의 경우 adjustResize @Jaap에서와 FragmentActivity 가능 솔루션 나를 위해 일을하지 않습니다.

내 해결책은 다음과 같습니다.

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    private int contentDiff;
    private int rootHeight;
    @Override
    public void onGlobalLayout() {
        View contentView = getWindow().findViewById(Window.ID_ANDROID_CONTENT);
        if (rootHeight != mDrawerLayout.getRootView().getHeight()) {
            rootHeight = mDrawerLayout.getRootView().getHeight();
            contentDiff = rootHeight - contentView.getHeight();
            return;
        }
        int newContentDiff = rootHeight - contentView.getHeight();
        if (contentDiff != newContentDiff) {
            if (contentDiff < newContentDiff) {
                onShowKeyboard(newContentDiff - contentDiff);
            } else {
                onHideKeyboard();
            }
            contentDiff = newContentDiff;
        }
    }
};

1

다른 접근 방식은 사용자가 입력을 중지했을 때 확인하는 것입니다 ...

TextEdit에 포커스가있을 때 (사용자가 입력하고 있었을 때) 뷰를 숨길 수 있습니다 (포커스 리스너)

Handler + Runnable 및 텍스트 변경 리스너를 사용하여 키보드를 닫고 (시각에 상관없이) 지연 후보기를 표시하십시오.

주목해야 할 것은 사용하는 지연이며,이 텍스트 편집기의 내용에 따라 다릅니다.

Handler timeoutHandler = new Handler();
Runnable typingRunnable = new Runnable() {
    public void run() {
        // current TextEdit
        View view = getCurrentFocus();

        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        // reset focus
        view.clearFocus();
        // close keyboard (whether its open or not)
        imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);

        // SET VIEWS VISIBLE
    }
};

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            // SET VIEWS GONE

            // reset handler
            timeoutHandler.removeCallbacks(typingRunnable);
            timeoutHandler.postDelayed(typingRunnable, TYPING_TIMEOUT);
        }
    }
});

editText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // Reset Handler...
        timeoutHandler.removeCallbacks(typingRunnable);
    }

    @Override
    public void afterTextChanged(Editable s) {
        // Reset Handler Cont.
        if (editText.getText().toString().trim().length() > 0) {
            timeoutHandler.postDelayed(typingRunnable, TYPING_TIMEOUT);
        }
    }
});

1

이 코드는 훌륭하게 작동합니다

루트보기 에이 클래스를 사용하십시오 :

public class KeyboardConstraintLayout extends ConstraintLayout {

private KeyboardListener keyboardListener;
private EditText targetEditText;
private int minKeyboardHeight;
private boolean isShow;

public KeyboardConstraintLayout(Context context) {
    super(context);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); //128dp
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); // 128dp
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); // 128dp
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (!isInEditMode()) {
        Activity activity = (Activity) getContext();
        @SuppressLint("DrawAllocation")
        Rect rect = new Rect();
        getWindowVisibleDisplayFrame(rect);

        int statusBarHeight = rect.top;
        int keyboardHeight = activity.getWindowManager().getDefaultDisplay().getHeight() - (rect.bottom - rect.top) - statusBarHeight;

        if (keyboardListener != null && targetEditText != null && targetEditText.isFocused()) {
            if (keyboardHeight > minKeyboardHeight) {
                if (!isShow) {
                    isShow = true;
                    keyboardListener.onKeyboardVisibility(true);
                }
            }else {
                if (isShow) {
                    isShow = false;
                    keyboardListener.onKeyboardVisibility(false);
                }
            }
        }
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

public boolean isShowKeyboard() {
    return isShow;
}

public void setKeyboardListener(EditText targetEditText, KeyboardListener keyboardListener) {
    this.targetEditText = targetEditText;
    this.keyboardListener = keyboardListener;
}

public interface KeyboardListener {
    void onKeyboardVisibility (boolean isVisible);
}

}

활동 또는 단편에서 키보드 리스너를 설정하십시오.

        rootLayout.setKeyboardListener(targetEditText, new KeyboardConstraintLayout.KeyboardListener() {
        @Override
        public void onKeyboardVisibility(boolean isVisible) {

        }
    });


0

불행히도 Jaap van Hengstum의 답변에 대해 언급 할만 큼 충분히 높은 평판을 얻지 못했습니다. 하지만 문제를 가진 사람들의 몇 가지 의견을 읽고 contentViewTop항상 0하고 있음을onShowKeyboard(...) 항상 불려지는 .

나는 같은 문제가 있었고 내가 가진 문제를 알아 냈습니다. 나는 AppCompatActivity'normal'대신을 사용했습니다 Activity. 이 경우 Window.ID_ANDROID_CONTENT지칭 ContentFrameLayout아닌로 FrameLayout오른쪽 상단 값. 내 경우에는 '정상'을 사용하려면 괜찮다고 Activity다른 활동 유형을 사용하는 경우 (난 그냥 테스트, AppCompatActivity어쩌면 그것은 또한 같은 다른 acitivy-유형의 문제입니다, FragmentActivity당신은에 액세스 할 수 있습니다) FrameLayout이다, 의 조상 ContentFrameLayout.


0

키보드 쇼 때

rootLayout.getHeight() < rootLayout.getRootView().getHeight() - getStatusBarHeight() 

그렇지 않다면, 숨기기


0
private boolean isKeyboardShown = false;
private int prevContentHeight = 0;
private ViewGroup contentLayout;

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener =
        new ViewTreeObserver.OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        int contentHeight = contentLayout.getHeight();
        int rootViewHeight = contentLayout.getRootView().getHeight();

        if (contentHeight > 0) {

            if (!isKeyboardShown) {
                if (contentHeight < prevContentHeight) {
                    isKeyboardShown = true;
                    onShowKeyboard(rootViewHeight - contentHeight);
                }
            } else {
                if (contentHeight > prevContentHeight) {
                    isKeyboardShown = false;
                    onHideKeyboard();
                }
            }

            prevContentHeight = contentHeight;
        }
    }
};

Jaap의 승인 된 답변을 약간 수정했습니다. 그러나 제 경우에는 같은 가정이 거의 android:windowSoftInputMode=adjustResize없으며 앱이 시작될 때 키보드가 처음에 나타나지 않습니다. 또한, 관련 화면이 부모의 키와 일치한다고 가정합니다.

contentHeight > 0이 확인을 통해 관련 화면이 숨겨 지거나이 특정 화면에 대한 키보드 이벤트 청취를 적용하도록 표시되는지 알 수 있습니다. 또한 attachKeyboardListeners(<your layout view here>)주요 활동의 onCreate()방법으로 관련 화면의 레이아웃보기를 전달합니다 . 관련 화면의 높이가 바뀔 때마다prevContentHeight 변수를 나중에 키보드가 표시되는지 숨겨져 있는지 확인합니다.

나를 위해, 지금까지 꽤 잘 작동했습니다. 나는 그것이 다른 사람들에게도 효과가 있기를 바랍니다.


0

"Jaap van Hengstum"의 답변이 저에게 효과적이지만 방금 말한대로 "android : windowSoftInputMode"를 설정할 필요는 없습니다!

나는 그것을 더 작게 만들었습니다 (지금은 내가 원하는 것을 감지합니다. 실제로 키보드 표시 및 숨기기에 대한 이벤트).

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
        int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
        if(heightDiff <= contentViewTop){
            onHideKeyboard();
        } else {
            onShowKeyboard();
        }
    }
};

private boolean keyboardListenersAttached = false;
private ViewGroup rootLayout;

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

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

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

    keyboardListenersAttached = true;
}

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

    if (keyboardListenersAttached) {
        rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
    }
}

그리고 이것을 추가하는 것을 잊지 마십시오

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_comments);
    attachKeyboardListeners();}

0

이것은 활동을 변경할 필요없이 작동합니다. android:windowSoftInputMode

1 단계 : EditText 클래스를 확장하고 다음 두 가지를 재정의하십시오.

@Override
public void setOnEditorActionListener(final OnEditorActionListener listener) {
    mEditorListener = listener;
    super.setOnEditorActionListener(listener);
}

@Override
public boolean onKeyPreIme(final int keyCode, final KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        if (mEditorListener != null) {
            mEditorListener.onEditorAction(this, android.R.id.closeButton, event);
        }
    }
    return super.onKeyPreIme(keyCode, event);
}

2 단계 : 활동에서이 두 가지를 작성하십시오.

private void initKeyboard() {
    final AppEditText editText = findViewById(R.id.some_id);
    editText.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            setKeyboard(hasFocus);
        }
    });
    editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (event == null || event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                editText.clearFocus();
            }
            return false;
        }
    });
}

public void setKeyboard(boolean isShowing) {
    // do something
}

*** clearFocus일을하려면 부모 계층의 부모 나 첫 번째 자녀가 집중할 수 있도록해야합니다.

    setFocusableInTouchMode(true);
    setFocusable(true);

0

이것은 원하는대로 작동하지 않습니다 ...

... 확인하기 위해 많은 사용 크기 계산을 보았습니다 ...

나는 그것이 열려 있는지 확인하고 싶었 여부와 내가 발견 isAcceptingText()

그래서 이것은 실제로 개방 또는 폐쇄와 같은 개방 또는 폐쇄를 다루지 않으므로 다양한 시나리오에서 다른 사람들을 도울 수있는 관련 코드입니다 ...

활동 중

    if (((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
    } else {
        Log.d(TAG,"Software Keyboard was not shown");
    }

파편으로

    if (((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)).isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
    } else {
        Log.d(TAG,"Software Keyboard was not shown");

    }

0

아래 코드로 확인하십시오 :

XML 코드 :

<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorParent"
    style="@style/parentLayoutPaddingStyle"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  .................


</android.support.constraint.ConstraintLayout>

자바 코드 :

//Global Variable
android.support.constraint.ConstraintLayout activityRootView;
boolean isKeyboardShowing = false;
private  ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener;
android.support.constraint.ConstraintLayout.LayoutParams layoutParams;




 //onCreate or onViewAttached
    activityRootView = view.findViewById(R.id.coordinatorParent);
        onGlobalLayoutListener = onGlobalLayoutListener();
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);


  //outside oncreate
  ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener() {
        return new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                activityRootView.getWindowVisibleDisplayFrame(r);
                int screenHeight = activityRootView.getRootView().getHeight();
                int keypadHeight = screenHeight - r.bottom;

                if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
                    if (!isKeyboardShowing) {  // keyboard is opened
                        isKeyboardShowing = true;
                        onKeyboardVisibilityChanged(true);
                   }
                }
                else {
                    if (isKeyboardShowing) {   // keyboard is closed
                        isKeyboardShowing = false;
                        onKeyboardVisibilityChanged(false);
                    }
                }
            }//ends here
        };

    }


    void onKeyboardVisibilityChanged(boolean value) {
        layoutParams = (android.support.constraint.ConstraintLayout.LayoutParams)topImg.getLayoutParams();

        if(value){
           int length = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90, getResources().getDisplayMetrics());
            layoutParams.height= length;
            layoutParams.width = length;
            topImg.setLayoutParams(layoutParams);
            Log.i("keyboard " ,""+ value);
        }else{
            int length1 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 175, getResources().getDisplayMetrics());
            layoutParams.height= length1;
            layoutParams.width = length1;
            topImg.setLayoutParams(layoutParams);
            Log.i("keyboard " ,""+ value);
        }
    }


    @Override
    public void onDetach() {
        super.onDetach();
        if(onGlobalLayoutListener != null) {
            activityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.