Intereting Posts

Android 4.4 – Прозрачные статусные / навигационные полосы – fitsSystemWindows / clipToPadding не работают через транзакции фрагментов

При использовании полупрозрачного статуса и навигационных полос из новых Android 4.4 KitKat API, установка fitsSystemWindows="true" и clipToPadding="false" в ListView работает изначально. fitsSystemWindows="true" сохраняет список под панелью действий и над навигационной панелью, clipToPadding="false" позволяет прокручивать список под прозрачной навигационной панелью и делает последний элемент в списке прокручивается достаточно далеко, чтобы пройти навигацию бар.

Однако при замене содержимого другим Fragment через FragmentTransaction эффект fitsSystemWindows уходит, а фрагмент попадает под панель действий и панель навигации.

У меня есть кодовая база демо-исходного кода вместе с загружаемым APK в качестве примера: https://github.com/afollestad/kitkat-transparency-demo . Чтобы узнать, о чем я говорю, откройте демонстрационное приложение с устройства, использующего KitKat, коснитесь элемента в списке (который откроет другое действие) и коснитесь элемента в открывшемся новом действии. Фрагмент, который заменяет содержимое, находится под панелью действий, и clipToPadding работает некорректно (панель навигации закрывает последний элемент в списке, когда вы прокручиваете весь путь вниз).

Есть идеи? Любые разъяснения нужны? Я опубликовал скриншоты до и после моего личного приложения, которое было разработано для моего работодателя.

ОдинДва

Solutions Collecting From Web of "Android 4.4 – Прозрачные статусные / навигационные полосы – fitsSystemWindows / clipToPadding не работают через транзакции фрагментов"

Вчера я боролся с той же проблемой. Много подумав, я нашел элегантное решение этой проблемы.

Во-первых, я видел метод requestFitSystemWindows() в ViewParent и я попытался вызвать его в onActivityCreated() фрагмента (после того, как фрагмент привязан к иерархии представлений), но, к сожалению, это не повлияло. Я хотел бы увидеть конкретный пример того, как использовать этот метод.

Затем я нашел аккуратное обходное решение: я создал пользовательский FitsSystemWindowsFrameLayout который я использую в качестве контейнера фрагментов в своих макетах, в качестве замены для замены классического FrameLayout . То, что он делает, это запоминание вставки окна, когда система fitSystemWindows() вызывается системой, затем она снова fitSystemWindows() вызов его дочернему макету (макет фрагмента) сразу же после добавления / присоединения фрагмента.

Вот полный код:

 public class FitsSystemWindowsFrameLayout extends FrameLayout { private Rect windowInsets = new Rect(); private Rect tempInsets = new Rect(); public FitsSystemWindowsFrameLayout(Context context) { super(context); } public FitsSystemWindowsFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public FitsSystemWindowsFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected boolean fitSystemWindows(Rect insets) { windowInsets.set(insets); super.fitSystemWindows(insets); return false; } @Override public void addView(View child, int index, ViewGroup.LayoutParams params) { super.addView(child, index, params); tempInsets.set(windowInsets); super.fitSystemWindows(tempInsets); } } 

Я думаю, что это намного проще и надежнее, чем хаки, которые пытаются определить размеры элементов пользовательского интерфейса, обращаясь к скрытым свойствам системы, которые могут меняться со временем, а затем вручную применять отступы к элементам.

Я решил проблему, используя библиотеку, которую я использую для набора цвета моей полупрозрачной строки состояния.

Класс SystemBarConfig SystemBarTint (см. Здесь https://github.com/jgilfelt/SystemBarTint#systembarconfig ) позволяет вам получать вставки, которые я устанавливал как дополнение к списку в каждом фрагменте, а также использование clipToPadding="false" в списке.

У меня есть детали того, что я сделал на этом посту: http://mindofaandroiddev.wordpress.com/2013/12/28/making-the-status-bar-and-navigation-bar-transparent-with-a-listview -он-андроид-4-4-KitKat /

Ладно, так что это невероятно странно. Недавно я столкнулся с этой проблемой, кроме моей, с помощью мягкой клавиатуры . Сначала он работает, но если я добавляю транзакцию фрагмента, android:fitsSystemWindows="true" больше не работает. Я пробовал все решения здесь, никто из них не работал для меня.

Вот моя проблема: Введите описание изображения здесь

Вместо того, чтобы переопределять мое мнение, это подталкивает мое мнение, и это проблема.

Однако мне повезло и случайно наткнулся на ответ, который сработал для меня!

Итак, вот он:

Прежде всего, моя тема приложения: Theme.AppCompat.Light.NoActionBar (если это актуально, возможно, это, android странно).

Мауриси указал на что-то очень интересное, поэтому я хотел проверить, что он сказал, правда или нет. То, что он сказал, было правдой и в моем случае … ЕСЛИ вы не добавите этот атрибут в свою деятельность в манифесте Android вашего приложения:

Введите описание изображения здесь

После добавления:

 android:windowSoftInputMode="adjustResize" 

К вашей деятельности, android:fitsSystemWindows="true" больше не игнорируется после транзакции фрагмента!

Тем не менее, я предпочитаю, чтобы вы android:fitsSystemWindows="true" НЕ на корневой макете вашего фрагмента. Одно из самых больших мест, где будет возникать эта проблема, – это если у вас есть EditText или ListView. Если вы застряли в этом затруднительном положении, как я, установили android:fitsSystemWindows="true" в дочернем корневом макете, например:

Введите описание изображения здесь

ДА, это решение работает на всех устройствах Lollipop и pre-lollipop.

И вот доказательство: Введите описание изображения здесь

Он изменяет размеры вместо того, чтобы нажимать макет вверх. Надеюсь, я помог кому-то, кто находится на той же лодке, что и я.

Спасибо вам большое!

Хедз-ап для некоторых людей сталкивается с этой проблемой.

Ключевой элемент информации с методом fitSystemWindows, который выполняет большую часть работы:

Прохождение этой функции вниз по иерархии является глубиной. Один и тот же объект вставки содержимого распространяется по иерархии, поэтому любые сделанные в нем изменения будут видны всеми следующими представлениями (включая потенциально выше в иерархии, поскольку это обход по глубине). Первое представление, которое возвращает true, отменяет весь обход.

Поэтому, если у вас есть какие-либо другие фрагменты с представлениями контента, для которых fitsSystemWindows установлен в true, флаг будет потенциально игнорироваться. Я бы подумал о том, чтобы сделать ваш контейнер-фрагмент содержащим флаг fitsSystemWindows, если это возможно. В противном случае вручную добавьте дополнение.

Я тоже очень сильно борюсь с этим. Я видел все ответы здесь. К сожалению, никто из них не исправлял мою проблему в 100% случаев. SystemBarConfig не работает всегда, так как он не может обнаружить панель на некоторых устройствах. Я посмотрел исходный код и нашел, где вставки хранятся внутри окна.

  Rect insets = new Rect(); Window window = getActivity().getWindow(); try { Class clazz = Class.forName("com.android.internal.policy.impl.PhoneWindow"); Field field = clazz.getDeclaredField("mDecor"); field.setAccessible(true); Object decorView = field.get(window); Field insetsField = decorView.getClass().getDeclaredField("mFrameOffsets"); insetsField.setAccessible(true); insets = (Rect) insetsField.get(decorView); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } 

Вот как их получить. Очевидно, что в Android L будет хороший способ получить эти вставки, но в то же время это может быть хорошим решением.

Я столкнулся с той же проблемой. Когда я заменяю Фрагмент. «FitsSystemWindows» не работает.

Я исправил код, добавив к вашему фрагменту

 @Override public void onViewCreated(final View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); AndroidUtil.runOnUIThread(new Runnable() { @Override public void run() { ((ViewGroup) getView().getParent()).setFitsSystemWindows(true); } }); } 

В сочетании с ответом @BladeCoder я создал класс FittedFrameLayout, который выполняет две функции:

  • Он не добавляет прокладки для себя
  • Он просматривает все виды внутри своего контейнера и добавляет для них дополнение, но останавливается на самом нижнем уровне (если обнаружен флаг fitssystemwindows, он не будет сканировать дочерний объект глубже, но все же на той же глубине или ниже).

     public class FittedFrameLayout extends FrameLayout { private Rect insets = new Rect(); public FittedFrameLayout(Context context) { super(context); } public FittedFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public FittedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public FittedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } protected void setChildPadding(View view, Rect insets){ if(!(view instanceof ViewGroup)) return; ViewGroup parent = (ViewGroup) view; if (parent instanceof FittedFrameLayout) ((FittedFrameLayout)parent).fitSystemWindows(insets); else{ if( ViewCompat.getFitsSystemWindows(parent)) parent.setPadding(insets.left,insets.top,insets.right,insets.bottom); else{ for (int i = 0, z = parent.getChildCount(); i < z; i++) setChildPadding(parent.getChildAt(i), insets); } } } @Override protected boolean fitSystemWindows(Rect insets) { this.insets = insets; for (int i = 0, z = getChildCount(); i < z; i++) setChildPadding(getChildAt(i), insets); return true; } @Override public void addView(View child, int index, ViewGroup.LayoutParams params) { super.addView(child, index, params); setChildPadding(child, insets); } } 

Я разрешаю этот вопрос в 4.4

 if(test){ Log.d(TAG, "fit true "); relativeLayout.setFitsSystemWindows(true); relativeLayout.requestFitSystemWindows(); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); }else { Log.d(TAG, "fit false"); relativeLayout.setFitsSystemWindows(false); relativeLayout.requestFitSystemWindows(); getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); }