Android 소프트 키보드 가 입력 상 자 를 막 는 최종 솔 루 션

머리말
개발 을 오래 하면 여러 가지 구 덩이 를 만 날 수 밖 에 없다.
안 드 로 이 드 가 개발 하 는 길에'소프트 키보드 가 입력 상 자 를 막 았 다'는 구 덩이 는 오 랜 시간 이 걸 리 는 큰 구덩이 라 고 할 수 있다.자,천천히 보 자.
입문 편
Base
가장 기본 적 인 상황 은 그림 에서 보 듯 이 페이지 밑 에 EditText 가 있 습 니 다.아무런 처리 도 하지 않 으 면 소프트 키보드 가 팝 업 될 때 EditText 를 막 을 수 있 습 니 다.
이러한 상황 에 대한 처 리 는 매우 간단 합 니 다.AndroidManifest 파일 에서 activity 설정:android:windowSoftInputMode 의 값 adjustPan 또는 adjustResize 만 있 으 면 됩 니 다.이렇게:

<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustPan" >
...
</activity>
일반적으로 그들 은 문 제 를 해결 할 수 있다.물론 adjustPan 과 adjustResize 의 효 과 는 약간 다르다.
adjustPan 은 전체 화면 을 위로 이동 시 켜 입력 상 자 를 드 러 내 고 인터페이스의 구 조 를 바 꾸 지 않 습 니 다.
adjustResize 는 부 드 러 운 키 보드 를 꺼 낸 후의 인터페이스 크기 를 다시 계산 하 는 것 으로 더 적은 인터페이스 영역 으로 내용 을 표시 하 는 것 과 같 습 니 다.입력 상 자 는 일반적으로 자 연 스 럽 게 포함 되 어 있 습 니 다.
↑↑↑OK,이 건 입문 일 뿐,기본적으로 지구 상의 모든 안 드 로 이 드 엔지니어 가 해결 할 수 있다.
서 두 르 지 말고 아래 를 봐~
웹 뷰 까지 해 볼 까요?구덩이 가 왔 다.
위의 입문 편 에서 소프트 키 보드 는 원생 의 EditText 에서 팝 업 을 촉발 합 니 다.한편,H5,Hybrid 가 거의 App 표지 가 되 었 을 때 우 리 는 흔히 볼 수 있 는 상황 은 소프트 키 보드 는 WebView 의 웹 페이지 요소 에 의 해 팝 업 되 는 것 이다.
상황 설명
이 럴 때 상황 은 복잡 해진 다.
우선 페이지 가 전체 화면 모드 가 아 닌 경우 activity 에 adjustPan 을 설정 하면 효력 을 상실 합 니 다.
그 다음으로 페이지 가 전체 화면 모드 인 경우 adjustPan 과 adjustResize 는 모두 효력 을 잃 습 니 다.
―설명 하 자 면 이곳 의 전체 화면 모드 는 바로 페이지 가 전체 화면 이다.애플 리 케 이 션 이나 activity 가 Fullscreen 테 마 를 사 용 했 고'상태 색 착색','몰입 식 상태 표시 줄','Immersive Mode'등 을 포함한다.한 마디 로 하면 기본적으로 앱 이 상태 표시 줄 의 통 제 를 스스로 받 으 면 이런 문제 가 발생 한다.
아래 의 이 표 는 구체 적 인 상황 을 간단하게 열거 할 수 있다.
表格
"왜 구덩이 라 고 했 어 요?"issue 5497”
위의 표 의 이러한 상황 은 구 글 이 기대 하 는 것 이 아니 라 이상 적 인 상황 은 당연히 그들 이 모두 정상적으로 효력 을 발생 할 수 있 기 때문에 이것 은 사실 안 드 로 이 드 시스템 자체 의 BUG 이다.
왜 문장 첫머리 에 이것 이 구덩이 라 고 말 합 니까?
이 버그 는 Android1.x 시대(2009 년)부터 보 고 됐 기 때문에 현재 의 Android 7.0(2016 년)까지 복구 되 지 않 았 다.
구덩이 일 뿐만 아니 라 공식 적 으로 파 낸 구덩이 라 고 할 수 있 습 니 다.
"issue 5497",자세 한 내용 전송 문☞문제 5497-android-webView adjustSize windowSoftInputMode breaks when activity is fullscreen-Android 오픈 소스 프로젝트-Issue Tracker-Google 프로젝트 호스 팅
물론 구 덩이 를 누가 파 든 결국 개발 자가 해결 해 야 한다.
구 덩이 를 만난 후 에는 피 하거나 메 울 수 있 는 두 가지 방법 이 있다.
구 덩이 를 피 하 는 자세
앞에서 보 듯 이 구덩이 가 생기 는 조건 은 WebView 가 있 는 activity 가 전체 화면 모드 나 adjustPan 모드 를 사용 한 것 이다.
그러면 구 덩이 를 피 하 는 자 세 는 매우 간단 하 다.
activity 에 WebView 가 있 으 면 전체 화면 모드 를 사용 하지 말고 windowSoftInputMode 값 을 adjustResize 로 설정 하면 되 잖 아 요.
어 때,쉽 지 않 아?
20130927092846557
그러나 어떤 때 는 전체 화면 모드 와 WebView 를 동시에 가 져 야 한다.이때 구 덩이 를 피하 면 안 된다.우 리 는 새로운 구 덩이 를 메 우 는 자세 가 필요 하 다.다행히 개발 자의 지혜 는 무궁 하 다.이 구덩이 가 생 긴 지 이렇게 여러 해 가 되 었 는데 도 누군가가 해결 방안 을 찾 았 다.
AndroidBug5497Workaround
저 는 개인 적 으로 가장 좋 은 해결 방안 은 이것 이 라 고 생각 합 니 다AndroidBug5497Workaround신기 한 AndroidBug 5497 Workaround 류 만 필요 합 니 다.
이름 을 보면 알 수 있 듯 이'5497'문 제 를 전문 적 으로 다 루 는 것 이 고 사용 절차 도 매우 간단 하 다.
프로젝트 에 AndroidBug 5497 Workaround 클래스 를 복사 합 니 다.
구 덩이 를 메 워 야 하 는 activity 의 onCreate 방법 에 AndroidBug 5497 Workaround.assist Activity(this)를 추가 하면 됩 니 다.
테스트 를 통 해 기본적으로 각 Android 버 전에 서 사용 할 수 있 으 며,효 과 는 기본적으로 adjustResize 를 설정 한 것 과 비슷 합 니 다.
대비 도 보기:
效果对比图
우리 공장 앱 의 한 웹 뷰 를 사용 하 는 전체 화면 모드 인 Activity 페이지 는 왼쪽 에서 오른쪽으로 각각 소프트 키보드 의 스타일,소프트 키보드 가 입력 상 자 를 막 는 효과,그리고 AndroidBug 5497 Workaround 를 사용 한 후의 최종 효과 입 니 다.
그것 의 원 리 는 무엇 입 니까?
이 시 크 한 AndroidBug 5497 Workaround 류 는 복잡 하지 않 습 니 다.몇 십 줄 의 코드 만 있 습 니 다.먼저 여기에 붙 입 니 다.

public class AndroidBug5497Workaround {
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static void assistActivity (Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard/4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);//      : return r.bottom
}
}
코드 는 대체로 이렇게 몇 가지 일 을 했다.
1.activity 의 루트 View 찾기
입구 의 코드 를 보십시오.

FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
그 중에서 첫 번 째 줄 의 android.R.id.content 가 가리 키 는 View 는 Android 모든 Activity 인터페이스 에서 개발 자가 제어 할 수 있 는 구역 의 루트 View 입 니 다.
Activity 가 전체 화면 모드 라면 android.R.id.content 는 모든 화면 영역 을 차지 합 니 다.
Activity 가 일반적인 비 전체 화면 모드 라면 android.R.id.content 는 상태 표시 줄 을 제외 한 모든 영역 을 차지 합 니 다.
다른 상황,예 를 들 어 Activity 는 팝 업 창 이나 7.0 이후 의 스크린 스타일 등 이 고 안 드 로 이 드 R.id.content 도 팝 업 창의 범위 나 스크린 이 있 는 반 화면 이다.이런 상황 이 비교적 적 으 면 잠시 고려 하지 않 는 다.
우리 가 자주 사용 하 는 set ContentView(View view)/setContent(int layRes)는 사실 우리 가 지정 한 View 나 layRes 를 android.R.id.content 에 넣 어 하위 View 가 되 는 것 입 니 다.
그래서 두 번 째 줄 content.getChildAt(0)에서 얻 은 mChildOf Content 는 우리 가 setContentView 로 넣 은 View 를 얻 는 데 사 용 됩 니 다.
2.Listener 감청 트 리 변경 설정

mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener({ //     
possiblyResizeChildOfContent();
});
View.getViewTreeObserver()는 ViewTreeObserver 대상 을 얻 을 수 있 습 니 다.이 대상 은 현재 View 트 리 에 발생 하 는 변 화 를 감청 하기 위해 관찰자 입 니 다.여기에 등 록 된 addOnGlobalLayoutListener 는 현재 View 트 리 의 전역 레이아웃(GlobalLayout)이 바 뀌 거나 그 중의 View 시각 상태 가 바 뀌 었 을 때 알림 을 되 돌려 줍 니 다.
"소프트 키보드 팝 업"은 이 사건 을 촉발 시 키 는 원천 입 니 다.(소프트 키보드 팝 업 은 GlobalLayout 를 변화 시 킬 수 있 습 니 다)
이 제 는'소프트 키보드 팝 업'사건 을 감청 할 수 있 게 됐다 는 것 이다.
3.인터페이스 변화 후"사용 가능 한 높이"획득
소프트 키보드 가 꺼 지면 다음 일 은 변 경 된 인터페이스의 사용 가능 한 높이 를 가 져 오 는 것 입 니 다(개발 자 에 의 해 내용 의 높이 를 표시 할 수 있 습 니 다).
코드 직접 보기:

private int computeUsableHeight() {
Rect rect = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(rect);
// rect.top         ,       ,   return rect.bottom    
return (rect.bottom - rect.top);
}
View.getWindow Visible DisplayFrame(Rect rect),이 코드 가 얻 을 수 있 는 Rect―즉 인터페이스 가 제목 표시 줄 을 제거 하고 소프트 키보드 에 가 려 진 부분 을 제거 하 며 남 은 사각형 영역―그림 에서 보 듯 이 빨 간 상자 의 영역.
Rect 영역 설명도
Rect区域示意图
또한 알 수 있다.
rect.top 값 은 제목 표시 줄 의 높이 입 니 다.실제로 제목 표시 줄 높이 를 얻 는 방법 으로 도 많이 사용 된다)
화면 높이-rect.bottom,소프트 키보드 높이 입 니 다.소프트 키보드 높이 를 얻 는 방법 도 나 타 났 다)
이때
전체 화면 모드 에서 사용 가능 한 높이=rect.bottom
전체 화면 모드 가 아 닌 높이=rect.bottom-rect.top 사용 가능
4.마지막 단계,높이 재 설정
우리 가 계산 한 사용 가능 한 높이 는 현재 시각 효과 에서 볼 수 있 는 인터페이스 높이 이다.그러나 현재 인터페이스의 실제 높이 는 사용 가능 한 높이 보다 소프트 키보드 의 거리 가 더 많다.
그래서 마지막 단 계 는 인터페이스 높이 를 사용 가능 한 높이 로 설정 하 는 것 이다.

private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard/4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
위의 코드 에'height Difference'(usable HeightSans Keyboard/4)라 는 판단 이 추가 되 었 습 니 다.이것 은 불필요 한 방 해 를 제거 하기 위 한 것 입 니 다.OnGlobalLayout 사건 을 촉발 할 수 있 는 원인 은 매우 많 기 때문에 소프트 키보드 의 팝 업 변화 뿐만 아니 라 각 피 드 View 의 숨겨 진 디 스 플레이 변화 등 도 포함 되 어 인터페이스 높이 에 미 치 는 영향 에 한계 가 있다.이 판단 을 더 한 후에 인터페이스의 높이 변화 가 1/4 의 화면 높이 를 초과 해 야 높이 를 재 설정 할 수 있 고 코드 가 소프트 키보드 의 팝 업 에 만 응답 할 수 있 습 니 다.
총결산
요약 하면 바로 이렇다.
일반 Activity(WebView 없 음),adjustpan 또는 adjustResize 를 직접 사용 합 니 다.
WebView 가 있 으 면:
a)전체 화면 모드 가 아니라면 adjustResize 를 사용 할 수 있 습 니 다.
b)전체 화면 모드 라면 AndroidBug 5497 Workaround 로 처리 합 니 다.
위 에서 말 한 것 은 소 편 이 소개 한 안 드 로 이 드 소프트 키보드 가 입력 상 자 를 막 는 궁극 적 인 해결 방안 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.소 편 은 제때에 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기