Я работаю над проектом Android и реализую панель навигации. Я читаю новые спецификации дизайна материалов и контрольный список дизайна материалов .
В спецификации сказано, что выдвижная панель должна плавать над всем остальным, включая строку состояния, и быть полупрозрачной над строкой состояния.
Моя панель навигации находится над строкой состояния, но не имеет прозрачности. Я следил за кодом из этого сообщения SO, как было предложено в блоге разработчиков Google, ссылка выше Как мне использовать DrawerLayout для отображения поверх ActionBar / Toolbar и под строкой состояния? .
Ниже мой макет XML
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/my_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/my_awesome_toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="@color/appPrimaryColour" />
</LinearLayout>
<LinearLayout android:id="@+id/linearLayout"
android:layout_width="304dp"
android:layout_height="match_parent"
android:layout_gravity="left|start"
android:fitsSystemWindows="true"
android:background="#ffffff">
<ListView android:id="@+id/left_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="singleChoice"></ListView>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
Ниже представлена тема моих приложений
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/appPrimaryColour</item>
<item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
<item name="colorAccent">@color/appPrimaryColour</item>
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>
</style>
Ниже представлена тема моих приложений v21
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/appPrimaryColour</item>
<item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
<item name="colorAccent">@color/appPrimaryColour</item>
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
Ниже мой метод onCreate
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
setSupportActionBar(toolbar);
mDrawerLayout = (DrawerLayout)findViewById(R.id.my_drawer_layout);
mDrawerList = (ListView)findViewById(R.id.left_drawer);
mDrawerLayout.setStatusBarBackgroundColor(
getResources().getColor(R.color.appPrimaryColourDark));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
LinearLayout linearLayout =
(LinearLayout)findViewById(R.id.linearLayout);
linearLayout.setElevation(30);
}
Ниже приведен снимок экрана моего навигационного ящика, показывающий, что верх не полупрозрачен.
Ответы:
Фон строки состояния белый, это фон вашего ящика
LinearLayout
. Зачем? Вы - настройкиfitsSystemWindows="true"
для себяDrawerLayout
иLinearLayout
внутри него. Это заставляет васLinearLayout
расширяться за строкой состояния (которая прозрачна). Таким образом, делаем фон для выдвижной части строки состояния белым.Если вы не хотите, чтобы ваш ящик выступал за строку состояния (хотите, чтобы фон для всей строки состояния был полупрозрачным), вы можете сделать две вещи:
1) Вы можете просто удалить любое значение фона из вашего
LinearLayout
и раскрасить фон вашего контента внутри него. Или2) Вы можете удалить
fitsSystemWindows="true"
из своегоLinearLayout
. Я считаю, что это более логичный и понятный подход. Вы также избежите отбрасывания тени под строкой состояния, где панель навигации не расширяется.Если вы хотите, чтобы ваш ящик выступал за строку состояния и имел полупрозрачный оверлей размером с строку состояния, вы можете использовать a
ScrimInsetFrameLayout
в качестве контейнера для содержимого вашего ящика (ListView
) и установить фон строки состояния с помощьюapp:insetForeground="#4000"
. Конечно, вы можете измениться#4000
на все, что захотите. Не забывай оставатьсяfitsSystemWindows="true"
здесь!Или, если вы не хотите накладывать свой контент и отображать только сплошной цвет, вы можете просто установить для своего фона
LinearLayout
все, что захотите. Не забудьте установить фон вашего контента отдельно!РЕДАКТИРОВАТЬ: вам больше не нужно заниматься этим. Пожалуйста, обратитесь к Библиотеке поддержки дизайна, чтобы упростить реализацию навигационного ящика / представления.
источник
Все, что вам нужно сделать, это использовать какой-то полупрозрачный цвет для строки состояния. Добавьте эти строки в свою тему v21:
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@color/desired_color</item>
Не забывайте, что
color
(ресурс) всегда должен быть в формате#AARRGGBB
. Это означает, что цвет также будет включать альфа-значение.источник
Почему бы не использовать что-то подобное?
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" > <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent"/> <ListView android:id="@+id/left_drawer" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" android:background="#80111111"/> </android.support.v4.widget.DrawerLayout>
В приведенном выше коде используется альфа-ресурс в,
android:background
чтобы иметь возможность отображать прозрачность на панели действий.Как показывают другие ответы, есть и другие способы сделать это с помощью кода. Мой ответ выше делает необходимое в файле макета xml, который, на мой взгляд, легко редактируется.
источник
Все упомянутые здесь ответы слишком старые и длинные. Лучшее и краткое решение, которое работает с последней версией Navigationview, -
@Override public void onDrawerSlide(View drawerView, float slideOffset) { super.onDrawerSlide(drawerView, slideOffset); try { //int currentapiVersion = android.os.Build.VERSION.SDK_INT; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){ // Do something for lollipop and above versions Window window = getWindow(); // clear FLAG_TRANSLUCENT_STATUS flag: window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); // finally change the color to any color with transparency window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDarktrans));} } catch (Exception e) { Crashlytics.logException(e); } }
это изменит цвет вашей строки состояния на прозрачный, когда вы откроете ящик
Теперь, когда вы закрываете ящик, вам нужно снова изменить цвет строки состояния на темный, поэтому вы можете сделать это таким образом.
@Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); try { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { // Do something for lollipop and above versions Window window = getWindow(); // clear FLAG_TRANSLUCENT_STATUS flag: window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); // finally change the color again to dark window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark)); } } catch (Exception e) { Crashlytics.logException(e); } }
а затем в основном макете добавьте одну строку, т.е.
android:fitsSystemWindows="true"
и ваш макет ящика будет выглядеть как
<android.support.v4.widget.DrawerLayout 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:id="@+id/drawer_layout" android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent">
и ваш вид навигации будет выглядеть как
<android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_height="match_parent" android:layout_width="wrap_content" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/navigation_header" app:menu="@menu/drawer" />
Я протестировал его, и он полностью работает. Надеюсь, он кому-то поможет. Возможно, это не лучший подход, но он работает плавно и прост в реализации. Отметьте это, если это поможет. Удачного кодирования :)
источник
Вам нужно обернуть макет панели навигации в файл
ScrimLayout
.A в
ScrimLayout
основном рисует полупрозрачный прямоугольник над макетом панели навигации. Чтобы получить размер вставки, просто переопределитеfitSystemWindows
в вашемScrimLayout
.@Override protected boolean fitSystemWindows(Rect insets) { mInsets = new Rect(insets); return true; }
Позже переопределите,
onDraw
чтобы нарисовать полупрозрачный прямоугольник.Пример реализации можно найти в источнике Google IO App. Здесь вы можете увидеть, как он используется в макете xml.
источник
Если вы хотите, чтобы панель навигации находилась над строкой состояния и была полупрозрачной над строкой состояния. Google I / O Android App Source предоставляет хорошее решение ( APK в Play Store не обновляются до последней версии)
Сначала вам понадобится ScrimInsetFrameLayout
/* * Copyright 2014 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome * (status and navigation bars, overlay action bars). */ public class ScrimInsetsFrameLayout extends FrameLayout { private Drawable mInsetForeground; private Rect mInsets; private Rect mTempRect = new Rect(); private OnInsetsCallback mOnInsetsCallback; public ScrimInsetsFrameLayout(Context context) { super(context); init(context, null, 0); } public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ScrimInsetsView, defStyle, 0); if (a == null) { return; } mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsView_insetForeground); a.recycle(); setWillNotDraw(true); } @Override protected boolean fitSystemWindows(Rect insets) { mInsets = new Rect(insets); setWillNotDraw(mInsetForeground == null); ViewCompat.postInvalidateOnAnimation(this); if (mOnInsetsCallback != null) { mOnInsetsCallback.onInsetsChanged(insets); } return true; // consume insets } @Override public void draw(Canvas canvas) { super.draw(canvas); int width = getWidth(); int height = getHeight(); if (mInsets != null && mInsetForeground != null) { int sc = canvas.save(); canvas.translate(getScrollX(), getScrollY()); // Top mTempRect.set(0, 0, width, mInsets.top); mInsetForeground.setBounds(mTempRect); mInsetForeground.draw(canvas); // Bottom mTempRect.set(0, height - mInsets.bottom, width, height); mInsetForeground.setBounds(mTempRect); mInsetForeground.draw(canvas); // Left mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom); mInsetForeground.setBounds(mTempRect); mInsetForeground.draw(canvas); // Right mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom); mInsetForeground.setBounds(mTempRect); mInsetForeground.draw(canvas); canvas.restoreToCount(sc); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (mInsetForeground != null) { mInsetForeground.setCallback(this); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mInsetForeground != null) { mInsetForeground.setCallback(null); } } /** * Allows the calling container to specify a callback for custom processing when insets change (i.e. when * {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on * UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set * clipToPadding to false. */ public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) { mOnInsetsCallback = onInsetsCallback; } public static interface OnInsetsCallback { public void onInsetsChanged(Rect insets); } }
Затем в вашем XML-макете измените эту часть
<LinearLayout android:id="@+id/linearLayout" android:layout_width="304dp" android:layout_height="match_parent" android:layout_gravity="left|start" android:fitsSystemWindows="true" android:background="#ffffff"> <ListView android:id="@+id/left_drawer" android:layout_width="match_parent" android:layout_height="match_parent" android:choiceMode="singleChoice"></ListView> </LinearLayout>
Измените LinearLayout на свой ScrimInsetFrameLayout следующим образом
<com.boardy.util.ScrimInsetFrameLayout xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/linearLayout" android:layout_width="304dp" android:layout_height="match_parent" android:layout_gravity="left|start" android:fitsSystemWindows="true" app:insetForeground="#4000"> <ListView android:id="@+id/left_drawer" android:layout_width="match_parent" android:layout_height="match_parent" android:choiceMode="singleChoice"></ListView> </com.boardy.util.ScrimInsetFrameLayout>
источник
ScrimInsetsView_insetForeground
атрибут.android.support.design.internal.ScrimInsetsFrameLayout
из библиотеки поддержкиМне нужно было реализовать аналогичную функцию в моем проекте. И чтобы сделать мой ящик прозрачным, я просто использую прозрачность для шестнадцатеричных цветов . Используя 6 шестнадцатеричных цифр, у вас есть 2 шестнадцатеричные цифры для каждого значения красного, зеленого и синего соответственно. но если вы поместите две дополнительные цифры (8 шестнадцатеричных цифр), у вас будет ARGB (две цифры для альфа-значения) ( смотрите здесь ).
Вот значения непрозрачности в шестнадцатеричном формате: для 2 дополнительных цифр
100% — FF 95% — F2 90% — E6 85% — D9 80% — CC 75% — BF 70% — B3 65% — A6 60% — 99 55% — 8C 50% — 80 45% — 73 40% — 66 35% — 59 30% — 4D 25% — 40 20% — 33 15% — 26 10% — 1A 5% — 0D 0% — 00
Например: если у вас есть шестнадцатеричный цвет (# 111111), просто установите одно из значений непрозрачности, чтобы получить прозрачность. вот так: (# 11111100)
Мой ящик не закрывает панель действий (как ваш), но прозрачность также может применяться в этих случаях. Вот мой код:
<ListView android:id="@+id/left_drawer" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:background="#11111100" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" /> </android.support.v4.widget.DrawerLayout>
А вот еще одна статья, которая поможет вам разобраться в альфа-кодах шестнадцатеричных цветов.
источник
Существующие решения довольно устарели. Вот последнее решение, которое должно отлично работать с AndroidX или библиотеками материалов.
Добавьте
android:fitsSystemWindows="true"
в корневой вид вашего макета, который в вашем случае является DrawerLayout.Это указывает представлению использовать весь экран для измерения и макета, перекрывая строку состояния.
Добавьте в свой стиль XML следующее
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowTranslucentStatus">true</item>
windowTranslucentStatus
сделает строку состояния прозрачной,windowDrawsSystemBarBackgrounds
указывает строке состояния рисовать что-либо под ней, вместо того, чтобы быть черной пустотой.Позвоните
DrawerLayout.setStatusBarBackground()
илиDrawerLayout.setStatusBarBackgroundColor()
в своей основной деятельностиЭто сообщает DrawerLayout о необходимости раскрасить область строки состояния.
источник
Выше были хорошие решения, но в моем случае они не сработали,
мой случай: в строке состояния уже установлен желтый цвет с использованием стилей, он не полупрозрачный. и цвет моего навигационного ящика белый, теперь, когда я рисую свой навигационный ящик, он всегда находится за строкой состояния и панелью навигации, так как цвет панели навигации также установлен.
цель: изменить цвет строки состояния и панели навигации при открытии панели навигации и восстановить ее при закрытии.
решение :
binding.drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() { @Override public void onDrawerSlide(@NonNull View drawerView, float slideOffset) { } @Override public void onDrawerOpened(@NonNull View drawerView) { getWindow().setStatusBarColor(getResources().getColor(R.color.forground)); getWindow().setNavigationBarColor(getResources().getColor(R.color.forground)); } @Override public void onDrawerClosed(@NonNull View drawerView) { getWindow().setStatusBarColor(getResources().getColor(R.color.yellow)); getWindow().setNavigationBarColor(getResources().getColor(R.color.yellow)); } @Override public void onDrawerStateChanged(int newState) { } });
источник
Все ответы здесь очень сложны, позвольте мне дать вам простой простой код. Добавьте эту строку кода в свой стиль AppTheme, и вы получите серую полупрозрачную строку состояния, когда откроете ящик.
<item name="android:windowTranslucentStatus">true</item>
это заставит его работать.
источник