소프트 키보드가 활성화되어있을 때 레이아웃을 조정하기 위해 많은 연구를했으며 성공적으로 구현했지만 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
매니페스트 파일의 활동 태그에서 이것을 사용할 때 문제가 발생 합니다.
이를 위해 나는 사용했다 android:windowSoftInputMode="adjustPan|adjustResize|stateHidden"
다른 옵션을 사용했지만 운이 없습니다.
그 후 나는 구현했다 FullScreen
프로그래밍 방식으로 하고 다양한 레이아웃을 시도 FullScreen
했지만 모두 헛된 일을했습니다.
나는이 링크를 참조 하고이 문제와 관련된 많은 게시물을 보았습니다.
http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html
http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/
xml 코드는 다음과 같습니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/masterContainerView"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ffffff">
<ScrollView android:id="@+id/parentScrollView"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
<TextView android:id="@+id/setup_txt" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Setup - Step 1 of 3"
android:textColor="@color/top_header_txt_color" android:textSize="20dp"
android:padding="8dp" android:gravity="center_horizontal" />
<TextView android:id="@+id/txt_header" android:layout_width="fill_parent"
android:layout_height="40dp" android:text="AutoReply:"
android:textColor="@color/top_header_txt_color" android:textSize="14dp"
android:textStyle="bold" android:padding="10dp"
android:layout_below="@+id/setup_txt" />
<EditText android:id="@+id/edit_message"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Some text here." android:textSize="16dp"
android:textColor="@color/setting_editmsg_color" android:padding="10dp"
android:minLines="5" android:maxLines="6" android:layout_below="@+id/txt_header"
android:gravity="top" android:scrollbars="vertical"
android:maxLength="132" />
<ImageView android:id="@+id/image_bottom"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_below="@+id/edit_message" />
</LinearLayout>
</ScrollView>
<RelativeLayout android:id="@+id/scoringContainerView"
android:layout_width="fill_parent" android:layout_height="50px"
android:orientation="vertical" android:layout_alignParentBottom="true"
android:background="#535254">
<Button android:id="@+id/btn_save" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_alignParentRight="true"
android:layout_marginTop="7dp" android:layout_marginRight="15dp"
android:layout_below="@+id/edit_message"
android:text = "Save" />
<Button android:id="@+id/btn_cancel" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginTop="7dp"
android:layout_marginRight="10dp" android:layout_below="@+id/edit_message"
android:layout_toLeftOf="@+id/btn_save" android:text = "Cancel" />
</RelativeLayout>
</RelativeLayout>
소프트 키보드가 그림에 나타날 때 하단 2 버튼이 위로 올라 가기를 원합니다.
답변
yghm의 해결 방법을 기반으로 한 클래스의 문제를 해결할 수있는 편리한 클래스를 작성했습니다 (물론 소스 코드에 새 클래스를 추가 한 후). 하나의 라이너는 다음과 같습니다.
AndroidBug5497Workaround.assistActivity(this);
구현 클래스는 다음과 같습니다.
public class AndroidBug5497Workaround {
// For more information, see https://issuetracker.google.com/issues/36911528
// 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);
}
}
이것이 누군가를 돕기를 바랍니다.
답변
답변이 이미 선택되어 있고 버그로 알려진 문제이므로 “가능한 해결 방법”을 추가 할 것이라고 생각했습니다.
소프트 키보드가 표시되면 전체 화면 모드를 전환 할 수 있습니다. 이를 통해 “adjustPan”이 올바르게 작동합니다.
즉, 여전히 응용 프로그램 테마의 일부로 @android : style / Theme.Black.NoTitleBar.Fullscreen 을 사용 하고 활동 창 소프트 입력 모드의 일부로 stateVisible | adjustResize를 사용하지만 함께 작동하려면 전체 화면 모드로 전환해야합니다 키보드가 나타나기 전에.
다음 코드를 사용하십시오.
전체 화면 모드 끄기
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
전체 화면 모드 켜기
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
참고-영감은 다음과 같습니다. 전체 화면 모드에서 제목 숨기기
답변
나는 Joseph Johnson으로부터 해결책을 시도 했지만 다른 것과 마찬가지로 내용과 키보드 사이의 틈새에 부딪쳤다. 전체 화면 모드를 사용할 때 소프트 입력 모드가 항상 이동 하기 때문에 문제가 발생 합니다. 이 패닝은 소프트 입력에 의해 숨겨 질 입력 필드를 활성화 할 때 Joseph의 솔루션을 방해합니다.
소프트 입력이 나타나면 내용이 먼저 원래 높이를 기준으로 패닝 된 다음 Joseph의 솔루션이 요청한 레이아웃에 따라 크기가 조정됩니다. 크기 조정 및 후속 레이아웃은 패닝을 취소하지 않으므로 간격이 생깁니다. 전체 이벤트 순서는 다음과 같습니다.
- 글로벌 레이아웃 리스너
- 패닝
- 내용의 레이아웃 (= 내용의 실제 크기 조정)
패닝을 비활성화 할 수는 없지만 내용 높이를 변경하여 팬 오프셋을 0으로 설정할 수 있습니다. 패닝이 발생하기 전에 실행되기 때문에 리스너에서 수행 할 수 있습니다. 컨텐츠 높이를 사용 가능한 높이로 설정하면 깜박임이없는 부드러운 사용자 환경이 만들어집니다.
나는 또한 이것들을 변경했다. 이 중 하나라도 문제가 발생하면 알려주십시오.
- 사용 가능한 높이의 전환 결정
getWindowVisibleDisplayFrame
. 는Rect
불필요한 쓰레기의 약간을 방지하기 위해 캐시됩니다. - 리스너도 제거하십시오. 이 기능은 전체 화면 요구 사항이 다른 여러 조각에 활동을 재사용 할 때 유용합니다.
- 키보드를 표시하거나 숨기지 말고 항상 내용 높이를 보이는 디스플레이 프레임 높이로 설정하십시오.
Nexus 5와 16에서 24 사이의 API 레벨을 실행하는 화면에서 작은 화면에서 큰 화면으로 테스트되었습니다.
코드는 Kotlin으로 포팅되었지만 변경 사항을 Java로 다시 포팅하는 것은 간단합니다. 도움이 필요하면 알려주십시오.
class AndroidBug5497Workaround constructor(activity: Activity) {
private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
private val rootView = contentContainer.getChildAt(0)
private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams
private val viewTreeObserver = rootView.viewTreeObserver
private val listener = ViewTreeObserver.OnGlobalLayoutListener { possiblyResizeChildOfContent() }
private val contentAreaOfWindowBounds = Rect()
private var usableHeightPrevious = 0
// I call this in "onResume()" of my fragment
fun addListener() {
viewTreeObserver.addOnGlobalLayoutListener(listener)
}
// I call this in "onPause()" of my fragment
fun removeListener() {
viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
private fun possiblyResizeChildOfContent() {
contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
val usableHeightNow = contentAreaOfWindowBounds.height()
if (usableHeightNow != usableHeightPrevious) {
rootViewLayout.height = usableHeightNow
// Change the bounds of the root view to prevent gap between keyboard and content, and top of content positioned above top screen edge.
rootView.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom)
rootView.requestLayout()
usableHeightPrevious = usableHeightNow
}
}
}
답변
시스템 UI 접근 방식 ( https://developer.android.com/training/system-ui/immersive.html )을 사용하는 경우 간단하고 안정적인 솔루션을 찾았습니다 .
를 사용하는 경우에 작동합니다 ( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
예 : 사용중인 경우).CoordinatorLayout
.
그것은 작동하지 않습니다 WindowManager.LayoutParams.FLAG_FULLSCREEN
(당신은 또한에 테마로 설정할 수있는 하나 android:windowFullscreen
),하지만 당신은 유사한 효과를 얻을 수 있습니다 SYSTEM_UI_FLAG_LAYOUT_STABLE
( “같은 시각 효과있다” 워드 프로세서에 따라 )이 솔루션은 다시 작동합니다.
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
Marshmallow를 실행하는 장치에서 테스트했습니다.
핵심은 소프트 키보드가 시스템 창 (예 : 상태 표시 줄 및 탐색 표시 줄) 중 하나이므로 WindowInsets
시스템 에서 발송 한 정보는 정확하고 신뢰할 수있는 정보입니다.
DrawerLayout
상태 표시 줄 뒤에 그리는 것과 같은 유스 케이스의 경우 상단 삽입 만 무시하고 하단 키보드를 적용하는 하단 삽입을 적용하는 레이아웃을 만들 수 있습니다.
내 습관은 다음과 같습니다 FrameLayout
.
/**
* Implements an effect similar to {@code android:fitsSystemWindows="true"} on Lollipop or higher,
* except ignoring the top system window inset. {@code android:fitsSystemWindows="true"} does not
* and should not be set on this layout.
*/
public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout {
public FitsSystemWindowsExceptTopFrameLayout(Context context) {
super(context);
}
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(),
insets.getSystemWindowInsetBottom());
return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
} else {
return super.onApplyWindowInsets(insets);
}
}
}
그리고 그것을 사용하려면 :
<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your original layout here -->
</com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>
이것은 이론적으로 미친 수정없이 모든 장치에 대해 작동해야하며 임의의 1/3
또는 1/4
화면 크기를 참조 하려고하는 해킹보다 훨씬 좋습니다 .
(API 16 이상이 필요하지만 Lollipop +에서만 전체 화면을 사용하여 상태 표시 줄 뒤에 그리기 때문에이 경우 가장 좋은 솔루션입니다.)
답변
노트는 그 해주십시오 android:windowSoftInputMode="adjustResize"
때 작동하지 않습니다 WindowManager.LayoutParams.FLAG_FULLSCREEN
활동에 대해 설정됩니다. 두 가지 옵션이 있습니다.
-
활동에 대해 전체 화면 모드를 비활성화하십시오. 전체 화면 모드에서는 활동 크기가 조정되지 않습니다. xml (활동의 주제를 변경하여) 또는 Java 코드에서이를 수행 할 수 있습니다. onCreate () 메소드에 다음 행을 추가하십시오.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`
또는
-
전체 화면 모드를 달성하려면 다른 방법을 사용하십시오. onCreate () 메소드에 다음 코드를 추가하십시오.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); View decorView = getWindow().getDecorView(); // Hide the status bar. int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions);`
방법 -2는 Android 4.1 이상에서만 작동합니다.
답변
나는이 문제에 직면해야했고 HTC one, galaxy s1, s2, s3, note 및 HTC 센세이션을 확인하는 작업이있었습니다.
레이아웃의 루트 뷰에 글로벌 레이아웃 리스너를 배치
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
public void onGlobalLayout() {
checkHeightDifference();
}
});
거기에서 나는 높이 차이를 확인했고 화면의 높이 차이가 화면 높이의 3 분의 1보다 크면 키보드가 열려 있다고 가정 할 수 있습니다. 이 답변 에서 가져 왔습니다 .
private void checkHeightDifference(){
// get screen frame rectangle
Rect r = new Rect();
mRootView.getWindowVisibleDisplayFrame(r);
// get screen height
int screenHeight = mRootView.getRootView().getHeight();
// calculate the height difference
int heightDifference = screenHeight - (r.bottom - r.top);
// if height difference is different then the last height difference and
// is bigger then a third of the screen we can assume the keyboard is open
if (heightDifference > screenHeight/3 && heightDifference != mLastHeightDifferece) {
// keyboard visiblevisible
// get root view layout params
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
// set the root view height to screen height minus the height difference
lp.height = screenHeight - heightDifference;
// call request layout so the changes will take affect
.requestLayout();
// save the height difference so we will run this code only when a change occurs.
mLastHeightDifferece = heightDifference;
} else if (heightDifference != mLastHeightDifferece) {
// keyboard hidden
PFLog.d("[ChatroomActivity] checkHeightDifference keyboard hidden");
// get root view layout params and reset all the changes we have made when the keyboard opened.
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
lp.height = screenHeight;
// call request layout so the changes will take affect
mRootView.requestLayout();
// save the height difference so we will run this code only when a change occurs.
mLastHeightDifferece = heightDifference;
}
}
이것은 아마도 총알 증거가 아니며 어쩌면 일부 장치에서는 작동하지 않지만 저에게 효과적이며 도움이되기를 바랍니다.
답변
Joseph Johnson 솔루션을 구현했으며 제대로 작동했습니다.이 솔루션을 사용한 후 응용 프로그램의 서랍이 제대로 닫히지 않는 경우가 있습니다. 사용자가 편집 텍스트가있는 조각을 닫을 때 리스너 removeOnGlobalLayoutListener를 제거하는 기능을 추가했습니다.
//when the application uses full screen theme and the keyboard is shown the content not scrollable!
//with this util it will be scrollable once again
//http://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
public class AndroidBug5497Workaround {
private static AndroidBug5497Workaround mInstance = null;
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private ViewTreeObserver.OnGlobalLayoutListener _globalListener;
// 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 AndroidBug5497Workaround getInstance (Activity activity) {
if(mInstance==null)
{
synchronized (AndroidBug5497Workaround.class)
{
mInstance = new AndroidBug5497Workaround(activity);
}
}
return mInstance;
}
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
_globalListener = new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
possiblyResizeChildOfContent();
}
};
}
public void setListener()
{
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(_globalListener);
}
public void removeListener()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mChildOfContent.getViewTreeObserver().removeOnGlobalLayoutListener(_globalListener);
} else {
mChildOfContent.getViewTreeObserver().removeGlobalOnLayoutListener(_globalListener);
}
}
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);
}
}
내 편집 텍스트가있는 클래스를 사용합니다.
@Override
public void onStart()
{
super.onStart();
AndroidBug5497Workaround.getInstance(getActivity()).setListener();
}
@Override
public void onStop()
{
super.onStop();
AndroidBug5497Workaround.getInstance(getActivity()).removeListener();
}