EditText Keyboard show/hide 이벤트 잡기

Posted by ITPangPang
2016. 11. 25. 23:49 안드로이드(android)/위젯(Widget)


EditText Keyboard show/hide

이벤트 잡기


ㆍ 이번에는 아주 유용한 코드를 하나 소개해보려고 합니다.


ㆍ 제가 EditText의 키보드가 올라오는 시점을 잡아야되는

    상황이 있었는데, 검색하다가 코드가 너무 좋아서 

    공유하려고 합니다.



제가 아직

초보개발자라서 이렇게

느낄수도 있지만,


안드로이드를

1년이상 개발하면서

쉬운것 같은데.. 

은근히 어렵다고

생각한 부분이

EditText 부분입니다.


특히나 키보드 부분이죠..

SoftKeyboard가 올라왔을때

화면 재구성부터, focus 관련등등


어쨋든, 이번에 개발하면서

필요했던 부분이 EditText의

SoftKeyboard가 show/hide 되는순간을

잡아야되는 상황이었는데


처음에는

어렵다고 생각도 안했었습니다.

왜냐하면,

그냥 기본적으로

EditText가 포커스를 받으면,

키보드가 올라오니까...

et.setOnFocusChangeListener(new View.OnFocusChangeListener()
{
@Override
public void onFocusChange(View view, boolean hasFocus)
{
if(hasFocus)
{
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{
Toast.makeText(getApplication(),"키보드 올라옴",Toast.LENGTH_SHORT).show();
}
}, 500);
}
}
});

처음에는

잘되는줄 알았습니다.


그리고

위 코드로 어떤 상황에서는

제대로 문제없이 사용할 수 있습니다

(requestFocus()로 요리조리 하면서 제어하면)


그런데 제 상황에서는

focus로만은 문제해결이 어려운

상황이었습니다.

(좀 복잡하긴 하지만..

포커스 받은상태에서 back키를

눌러서 키보드를 내리는 상황이거나,

EditText를 여러개 사용할때, 

EditText에서 EditText로 포커스 이동시

키보드가 항상 올라와있는 문제 등등

복합적으로...)


그래서 문제해결을 하기 위해서

여기 사이트를 발견하고야 말았습니다.


일단 소개하기 전에...

가장 중요한 조건상황이 하나 있는데

android:windowSoftInputMode="adjustResize"

InputMode가 adjustResize이여야 합니다.


개발이 원래 그렇듯..

제 상황에서는 아주 문제없이 사용했습니다.

상황별로 안먹히는 경우가 있을수도 있습니다.

(안먹히면 onMeasure을 이용해서 해결하는

방법이 있습니다! 화이팅)


사이트에 들어가면 아주 친절하게

영어(..?)로 설명이 쫙 되있고,

또 한번더 친절하게

It is available here.

링크까지 걸어주셨습니다.


연결하면

gist.github에 아주 친절하게

풀코드가 나옵니다.



그럼 사용해보자!


링크에 있는

SoftKeyboard.java

코드설명은 생략하고 진행하겠습니다.

(다른분이 정성스럽게 짠 코드를..

여기에서 분석한다는게.. 사용방법만 보겠습니다)


이렇게 프로젝트를 하나 열어서

SoftKeyboard 클래스를 하나 만듭니다.

그리고 위에 링크를 참고해서

코드를 채워넣습니다.


그리고 링크에서 알려준데로

레이아웃 전체를 감싸고 있는

Linearlayout(또는 Relative 등등이 되겠죠)

에 id를 부여해서, SoftKeyboard에게 넘겨줘야합니다.


[activity_main.xml]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.tistory.itpangpang.edittextkeyboard.MainActivity">

<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="아이디를 입력하세요"
/>
<EditText
android:id="@+id/et_pw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="패스워드를 입력하세요"
/>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="로그인"/>
</LinearLayout>

전체를 감싸고 있는

LinearLayout에 ll이라는

id를 부여하였습니다.


그 다음 MainActivity에 이렇게 써봅니다.

public class MainActivity extends AppCompatActivity
{
SoftKeyboard softKeyboard;
LinearLayout ll;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ll = (LinearLayout)findViewById(R.id.ll);

InputMethodManager controlManager = (InputMethodManager)getSystemService(Service.INPUT_METHOD_SERVICE);
softKeyboard = new SoftKeyboard(ll, controlManager);

}
}


이제 가장 중요한 softKeyboard로

인한 화면변화에 대한 Callback 처리부분을

보겠습니다.

softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
@Override
public void onSoftKeyboardHide()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
@Override
public void run()
{
//키보드 내려왔을때
}
});
}

@Override
public void onSoftKeyboardShow()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
@Override
public void run()
{
//키보드 올라왔을때
}
});
}
});

아마 링크에는

new Handler() 이 부분이

없을텐데,


키보드 show/hide 순간에

화면변화 이벤트를 주기 위해서는

위와 같이 추가해주시면 됩니다.


그리고 해당 화면에서 벗어났을때

Keyboard Callback을 제거하기 위해

onDestroy에 unRegister 처리를 해줍니다.

@Override
public void onDestroy()
{
super.onDestroy();
softKeyboard.unRegisterSoftKeyboardCallback();
}


마지막으로 manifest에

windowSoftInputMode도 한번 더

adjustResize인지 확인해봅니다

여기까지 끝났으면

간단하게 키보드 show/hide가 되는 순간

Toast를 달아서 확인해보도록 하겠습니다.


완성 코드는 이렇게 되겠네요

import android.app.Service;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
{
SoftKeyboard softKeyboard;
LinearLayout ll;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ll = (LinearLayout)findViewById(R.id.ll);

InputMethodManager controlManager = (InputMethodManager)getSystemService(Service.INPUT_METHOD_SERVICE);
softKeyboard = new SoftKeyboard(ll, controlManager);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
@Override
public void onSoftKeyboardHide()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
@Override
public void run()
{
Toast.makeText(getApplication(),"키보드 내려감",Toast.LENGTH_SHORT).show();
}
});
}

@Override
public void onSoftKeyboardShow()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
@Override
public void run()
{
Toast.makeText(getApplication(),"키보드 올라감",Toast.LENGTH_SHORT).show();
}
});
}
});
}
@Override
public void onDestroy()
{
super.onDestroy();
softKeyboard.unRegisterSoftKeyboardCallback();
}
}


결과확인


잘 나왔죠? ㅎㅎ


저 같은 경우에는

EditText가 8개인 화면에서

각 EditText마다 키보드 올라왔을때의

화면구조를 전부다 다르게 하기 위해서

(키보드 올라오고 내려오고 할때 animation 등등...)


위 링크의 도움을 받고 + 터치이벤트 + getCurrentFocus

+ requestFocus() 등등 조합해서 해결하였습니다.


참고사이트 : https://felhr85.net/2014/05/04/catch-soft-keyboard-showhidden-events-in-android/


*이 글에서 문제가 되는 부분이 있다면 즉시 삭제조치하겠습니다.