WindowSoftInputMode = "adjustResize" не работает с полупрозрачным действием / navbar

У меня проблемы с полупрозрачной панелью действий / навигацией в новом Android KitKat (4.4) и windowSoftInputMode="adjustResize" .

Нормальное изменение InputMode для настройкиResize, приложение должно изменить размер самого себя, когда отображается клавиатура … но здесь это не будет! Если я удалю строки для прозрачного эффекта, изменится размер.

Поэтому, если клавиатура видна, мой ListView находится под ней, и я не могу получить доступ к последним элементам. (Только скрывая клавиатуру вручную)

AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="XYZ" android:versionCode="23" android:versionName="0.1" > <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="19" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.XYZStyle" > <activity android:name="XYZ" android:label="@string/app_name" android:windowSoftInputMode="adjustResize" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 

Значения-V19 / styles.xml

 <?xml version="1.0" encoding="utf-8"?> <resources> <style name="Theme.XYZStyle" parent="@style/Theme.AppCompat.Light"> <item name="android:windowTranslucentStatus">true</item> <item name="android:windowTranslucentNavigation">true</item> </style> </resources> 

fragment.xml

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@+id/listView_contacts" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:divider="@null" android:dividerHeight="0dp" android:drawSelectorOnTop="true" android:fastScrollAlwaysVisible="true" android:fastScrollEnabled="true" android:paddingBottom="@dimen/navigationbar__height" > </ListView> </RelativeLayout> 

Какие-нибудь идеи для этого?

Solutions Collecting From Web of "WindowSoftInputMode = "adjustResize" не работает с полупрозрачным действием / navbar"

Вам не хватает следующего свойства:

 android:fitsSystemWindows="true" 

В корневой RelativeLayout макета фрагмента.xml (или, возможно, на макете активности, не уверен, поскольку у нас нет полной структуры вашего приложения)

Здесь есть отчет об ошибке. Я нашел обходное решение, которое, от ограниченного тестирования, похоже, делает трюк без каких-либо последствий. Добавьте пользовательскую реализацию вашей корневой ViewGroup (я почти всегда использую FrameLayout , так что это то, что я тестировал) с логикой ниже. Затем используйте этот настраиваемый макет вместо корневого макета и убедитесь, что вы установили android:fitsSystemWindows="true" . Затем вы можете просто вызвать getInsets() любое время после компоновки (например, добавить OnPreDrawListener ), чтобы при необходимости отрегулировать остальную часть вашего макета для учета системных вкладок.

 import android.content.Context; import android.graphics.Rect; import android.os.Build; import android.util.AttributeSet; import android.widget.FrameLayout; import org.jetbrains.annotations.NotNull; /** * @author Kevin * Date Created: 3/7/14 * * https://code.google.com/p/android/issues/detail?id=63777 * * When using a translucent status bar on API 19+, the window will not * resize to make room for input methods (ie * {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and * {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are * ignored). * * To work around this; override {@link #fitSystemWindows(android.graphics.Rect)}, * capture and override the system insets, and then call through to FrameLayout's * implementation. * * For reasons yet unknown, modifying the bottom inset causes this workaround to * fail. Modifying the top, left, and right insets works as expected. */ public final class CustomInsetsFrameLayout extends FrameLayout { private int[] mInsets = new int[4]; public CustomInsetsFrameLayout(Context context) { super(context); } public CustomInsetsFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public CustomInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public final int[] getInsets() { return mInsets; } @Override protected final boolean fitSystemWindows(@NotNull Rect insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Intentionally do not modify the bottom inset. For some reason, // if the bottom inset is modified, window resizing stops working. // TODO: Figure out why. mInsets[0] = insets.left; mInsets[1] = insets.top; mInsets[2] = insets.right; insets.left = 0; insets.top = 0; insets.right = 0; } return super.fitSystemWindows(insets); } } 

Поскольку fitSystemWindow s устарел, обратитесь к приведенному ниже ответу, чтобы завершить обходной путь.

Ответ @kcoppock действительно полезен, но fitSystemWindows устарел на уровне API 20

Так как API 20 (KITKAT_WATCH) вы должны переопределить onApplyWindowInsets

 @Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { mInsets[0] = insets.getSystemWindowInsetLeft(); mInsets[1] = insets.getSystemWindowInsetTop(); mInsets[2] = insets.getSystemWindowInsetRight(); return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, insets.getSystemWindowInsetBottom())); } else { return insets; } } 

Это работало для того, чтобы я имел полупрозрачную строку состояния и настраивалResize в фрагменте:

  1. Создайте пользовательский RelativeLayout как @ Victor91 и @kcoppock.

  2. Используйте CustomRelativeLayout в качестве родительского макета для вашего фрагмента.

  3. Объявить тему с помощью android: windowTranslucentStatus = true

  4. Активность контейнера должна быть объявлена ​​в Manifest с помощью android: windowSoftInputMode = "adjustResize" и использовать объявленную тему

  5. Пожалуйста, используйте fitsSystemWindows в корневом расположении фрагмента!

    Public class CustomRelativeLayout расширяет RelativeLayout {private int [] mInsets = new int [4];

     public CustomRelativeLayout(Context context) { super(context); } public CustomRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { mInsets[0] = insets.getSystemWindowInsetLeft(); mInsets[1] = insets.getSystemWindowInsetTop(); mInsets[2] = insets.getSystemWindowInsetRight(); return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, insets.getSystemWindowInsetBottom())); } else { return insets; } } 

    }

     <com.blah.blah.CustomRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> 

У меня была та же проблема: у My Activity был ScrollView в виде корневого представления, и с полупрозрачной панелью состояния она не изменялась правильно, когда клавиатура показывала … и, как следствие, экран не прокручивал скрытые виды ввода.

Решение. Перемещено все (макет и логика действий) внутри нового фрагмента. Затем изменилось действие, чтобы включить этот фрагмент. Теперь все работает так, как ожидалось!

Это макет деятельности:

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/contentView" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" /> 

Основываясь на обходном пути Джозефа Джонсона в Android Как настроить макет в полноэкранном режиме, когда отображается экранная панель

onCreate() это в onCreate() после setContentView() в своей деятельности.

AndroidBug5497Workaround.assistActivity(this);

return (r.bottom - r.top); отличается от оригинальной замены return (r.bottom - r.top); С return r.bottom; В computeUsableHeight()

По какой-то причине я должен установить для моей активности атрибут fitsSystemWindows значение false .

Этот обход меня спас. Это хорошо для меня. Надежда может помочь вам.

Класс реализации:

 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; } } 

AndroidBug5497Workaround.java заботится о утечке памяти. Нужен ниже код

 getViewTreeObserver().removeOnGlobalLayoutListener(listener); 

Мой пример с использованием RxJava, который автоматически вызывает removeOnGlobalLayoutListener (), когда onPause () в жизненном цикле Activity

 public class MyActivity extends RxAppCompatActivity { // ... protected void onStart(){ super.onStart(); TRSoftKeyboardVisibility .changes(this) // activity .compose(this.<TRSoftKeyboardVisibility.ChangeEvent>bindUntilEvent(ActivityEvent.PAUSE)) .subscribe(keyboardEvent -> { FrameLayout content = (FrameLayout) findViewById(android.R.id.content); View firstChildView = content.getChildAt(0); firstChildView.getLayoutParams().height = keyboardEvent.viewHeight(); firstChildView.requestLayout(); // keyboardEvent.isVisible = keyboard visible or not // keyboardEvent.keyboardHeight = keyboard height // keyboardEvent.viewHeight = fullWindowHeight - keyboardHeight }); //... } package commonlib.rxjava.keyboard; import android.app.Activity; import android.view.View; import android.widget.FrameLayout; import kr.ohlab.android.util.Assert; import rx.Observable; public class TRSoftKeyboardVisibility { public static Observable<ChangeEvent> changes(Activity activity) { Assert.notNull(activity, "activity == null"); FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); View childOfContent = content.getChildAt(0); return Observable.create( new TRSoftKeyboardVisibilityEventOnSubscribe(childOfContent)); } public static final class ChangeEvent { private final int keyboardHeight; private final boolean visible; private final int viewHeight; public static ChangeEvent create(boolean visible, int keyboardHeight, int windowDisplayHeight) { return new ChangeEvent(visible, keyboardHeight, windowDisplayHeight); } private ChangeEvent(boolean visible, int keyboardHeight, int viewHeight) { this.keyboardHeight = keyboardHeight; this.visible = visible; this.viewHeight = viewHeight; } public int keyboardHeight() { return keyboardHeight; } public boolean isVisible() { return this.visible; } public int viewHeight() { return viewHeight; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ChangeEvent)) return false; ChangeEvent that = (ChangeEvent) o; if (keyboardHeight != that.keyboardHeight) return false; if (visible != that.visible) return false; return viewHeight == that.viewHeight; } @Override public int hashCode() { int result = keyboardHeight; result = 31 * result + (visible ? 1 : 0); result = 31 * result + viewHeight; return result; } @Override public String toString() { return "ChangeEvent{" + "keyboardHeight=" + keyboardHeight + ", visible=" + visible + ", viewHeight=" + viewHeight + '}'; } } } package commonlib.rxjava.keyboard; import android.graphics.Rect; import android.view.View; import android.view.ViewTreeObserver; import kr.ohlab.android.util.Assert; import rx.Observable; import rx.Subscriber; import rx.android.MainThreadSubscription; import timber.log.Timber; public class TRSoftKeyboardVisibilityEventOnSubscribe implements Observable.OnSubscribe<TRSoftKeyboardVisibility.ChangeEvent> { private final View mTopView; private int mLastVisibleDecorViewHeight; private final Rect mWindowVisibleDisplayFrame = new Rect(); public TRSoftKeyboardVisibilityEventOnSubscribe(View topView) { mTopView = topView; } private int computeWindowFrameHeight() { mTopView.getWindowVisibleDisplayFrame(mWindowVisibleDisplayFrame); return (mWindowVisibleDisplayFrame.bottom - mWindowVisibleDisplayFrame.top); } private TRSoftKeyboardVisibility.ChangeEvent checkKeyboardVisibility() { int windowFrameHeightNow = computeWindowFrameHeight(); TRSoftKeyboardVisibility.ChangeEvent event = null; if (windowFrameHeightNow != mLastVisibleDecorViewHeight) { int mTopViewHeight = mTopView.getHeight(); int heightDiff = mTopViewHeight - windowFrameHeightNow; Timber.e("XXX heightDiff=" + heightDiff); if (heightDiff > (mTopViewHeight / 4)) { event = TRSoftKeyboardVisibility.ChangeEvent.create(true, heightDiff, windowFrameHeightNow); } else { event = TRSoftKeyboardVisibility.ChangeEvent.create(false, 0, windowFrameHeightNow); } mLastVisibleDecorViewHeight = windowFrameHeightNow; return event; } return null; } public void call(final Subscriber<? super TRSoftKeyboardVisibility.ChangeEvent> subscriber) { Assert.checkUiThread(); final ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { TRSoftKeyboardVisibility.ChangeEvent event = checkKeyboardVisibility(); if( event == null) return; if (!subscriber.isUnsubscribed()) { subscriber.onNext(event); } } }; mTopView.getViewTreeObserver().addOnGlobalLayoutListener(listener); subscriber.add(new MainThreadSubscription() { @Override protected void onUnsubscribe() { mTopView.getViewTreeObserver().removeOnGlobalLayoutListener(listener); } }); } } 

У меня была проблема.

Я установил windowDrawsSystemBarBackgrounds в значение «true», и мое приложение должно отображаться в строке состояния.

Это моя тема деятельности.

 <item name="android:windowTranslucentStatus" tools:targetApi="KITKAT">false</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowTranslucentNavigation">true</item> <item name="android:statusBarColor">@android:color/transparent</item> 

И я получил помощь от блога jianshu . Вы можете читать код, но текст вроде меня. Я добавлю еще немного кода.

 public final class ZeroInsetsFrameLayout extends FrameLayout { private int[] mInsets = new int[4]; public ZeroInsetsFrameLayout(Context context) { super(context); } public ZeroInsetsFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public ZeroInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public final int[] getInsets() { return mInsets; } @Override public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { outLocalInsets.left = 0; outLocalInsets.top = 0; outLocalInsets.right = 0; return super.computeSystemWindowInsets(in, outLocalInsets); } @Override protected final boolean fitSystemWindows(@NonNull Rect insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Intentionally do not modify the bottom inset. For some reason, // if the bottom inset is modified, window resizing stops working. // TODO: Figure out why. mInsets[0] = insets.left; mInsets[1] = insets.top; mInsets[2] = insets.right; insets.left = 0; insets.top = 0; insets.right = 0; } return super.fitSystemWindows(insets); } } 

Это мой фрагмент.

 <com.dhna.widget.ZeroInsetsFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:background="@color/white"> <!-- your xml code --> </ZeroInsetsFrameLayout> 

Я хочу, чтобы это было полезно для вас. удачи!