Я видел в новой спецификации материала Side Nav spec, что вы можете отображать ящик над панелью действий и за панель состояния. Как я могу это реализовать?
Новая функциональность в рамках и поддержка libs позволяют именно это. Есть три «кусочка головоломки»:
fitsSystemWindows
так, чтобы оно было заложено за fitsSystemWindows
системы. Theme.Material
нормального состояния Status.Material, чтобы DrawerLayout мог там рисовать. Я предполагаю, что вы будете использовать новый appcompat.
Во-первых, ваш макет должен выглядеть так:
<!-- The important thing to note here is the added fitSystemWindows --> <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"> <!-- Your normal content view --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- We use a Toolbar so that our drawer can be displayed in front of the action bar --> <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="?attr/colorPrimary" /> <!-- The rest of your content view --> </LinearLayout> <!-- Your drawer view. This can be any view, LinearLayout is just an example. As we have set fitSystemWindows=true this will be displayed under the status bar. --> <LinearLayout android:layout_width="304dp" android:layout_height="match_parent" android:layout_gravity="left|start" android:fitsSystemWindows="true"> <!-- Your drawer content --> </LinearLayout> </android.support.v4.widget.DrawerLayout>
Затем в вашей деятельности / фрагменте:
public void onCreate(Bundled savedInstanceState) { super.onCreate(savedInstanceState); // Your normal setup. Blah blah ... // As we're using a Toolbar, we should retrieve it and set it // to be our ActionBar Toolbar toolbar = (...) findViewById(R.id.my_awesome_toolbar); setSupportActionBar(toolbar); // Now retrieve the DrawerLayout so that we can set the status bar color. // This only takes effect on Lollipop, or when using translucentStatusBar // on KitKat. DrawerLayout drawerLayout = (...) findViewById(R.id.my_drawer_layout); drawerLayout.setStatusBarBackgroundColor(yourChosenColor); }
Затем вам нужно убедиться, что DrawerLayout отображается за панель состояния. Вы делаете это, изменяя свои значения: v21 theme:
Значения-V21 / themes.xml
<style name="Theme.MyApp" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:windowTranslucentStatus">true</item> </style>
Примечание. Если используется <fragment android:name="fragments.NavigationDrawerFragment">
вместо
<LinearLayout android:layout_width="304dp" android:layout_height="match_parent" android:layout_gravity="left|start" android:fitsSystemWindows="true"> <!-- Your drawer content --> </LinearLayout>
Фактический макет, желаемый эффект будет достигнут, если вы fitsSystemWindows(boolean)
в представлении, которое вы возвращаете из метода onCreateView
.
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View mDrawerListView = inflater.inflate( R.layout.fragment_navigation_drawer, container, false); mDrawerListView.setFitsSystemWindows(true); return mDrawerListView; }
Теперь это может быть достигнуто с помощью новой библиотеки поддержки дизайна Android .
Вы можете увидеть пример приложения Cheesesquare от Chris Banes, который демонстрирует все новые функции.
Поскольку полного сообщения не найдено, вот как я достиг желаемого результата.
Сначала включите ScrimInsetsFrameLayout в свой проект.
/* * 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)}, ie 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 (ie when {@link #fitSystemWindows(Rect)} * is called. This is useful for setting padding on UI elements * based on UI chrome insets (eg 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); } }
Затем создайте стиль, чтобы можно было установить insetForeground
.
Значения / attrs.xml
<declare-styleable name="ScrimInsetsView"> <attr name="insetForeground" format="reference|color" /> </declare-styleable>
Обновите xml-файл своей активности и убедитесь, что android:fitsSystemWindows
установлен на true как на DrawerLayout
так и на ScrimInsetsFrameLayout
.
макет / activity_main.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".MainActivity"> <!-- The main content view --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- Your main content --> </LinearLayout> <!-- The navigation drawer --> <com.example.app.util.ScrimInsetsFrameLayout xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/scrimInsetsFrameLayout" android:layout_width="320dp" android:layout_height="match_parent" android:layout_gravity="start" android:background="@color/white" android:elevation="10dp" android:fitsSystemWindows="true" app:insetForeground="#4000"> <!-- Your drawer content --> </com.example.app.util.ScrimInsetsFrameLayout> </android.support.v4.widget.DrawerLayout>
Внутри метода onCreate вашей активности установите цвет фона строки состояния на макете ящика.
MainActivity.java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ... mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout); mDrawerLayout.setStatusBarBackgroundColor( getResources().getColor(R.color.primary_dark)); }
Наконец, обновите тему приложения, чтобы DrawerLayout
за панель состояния.
Значения-V21 / styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> </style>
Результат:
С выпуском последней библиотеки поддержки Android (rev 22.2.0) у нас есть библиотека поддержки дизайна и как часть этого нового представления под названием NavigationView . Поэтому вместо того, чтобы делать все самостоятельно с помощью ScrimInsetsFrameLayout
и всего остального, мы просто используем это представление, и все делается для нас.
Добавьте Design Support Library
в файл build.gradle
dependencies { // Other dependencies like appcompat compile 'com.android.support:design:22.2.0' }
Добавьте NavigationView
в DrawerLayout
:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <!-- this is important --> <!-- Your contents --> <android.support.design.widget.NavigationView android:id="@+id/navigation" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:menu="@menu/navigation_items" /> <!-- The items to display --> </android.support.v4.widget.DrawerLayout>
Создайте новый меню-ресурс в /res/menu
и добавьте элементы и значки, которые вы хотите отобразить:
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/nav_home" android:icon="@drawable/ic_action_home" android:title="Home" /> <item android:id="@+id/nav_example_item_1" android:icon="@drawable/ic_action_dashboard" android:title="Example Item #1" /> </group> <item android:title="Sub items"> <menu> <item android:id="@+id/nav_example_sub_item_1" android:title="Example Sub Item #1" /> </menu> </item> </menu>
Начните навигацию и обработайте события click:
public class MainActivity extends AppCompatActivity { NavigationView mNavigationView; DrawerLayout mDrawerLayout; // Other stuff private void init() { mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mNavigationView = (NavigationView) findViewById(R.id.navigation_view); mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { mDrawerLayout.closeDrawers(); menuItem.setChecked(true); switch (menuItem.getItemId()) { case R.id.nav_home: // TODO - Do something break; // TODO - Handle other items } return true; } }); } }
Обязательно установите android:windowDrawsSystemBarBackgrounds
and android:statusBarColor
в values-v21
иначе ваш ящик не будет отображаться «под» StatusBar
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Other attributes like colorPrimary, colorAccent etc. --> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> </style>
Добавьте заголовок в навигационное меню. Для этого просто создайте новый макет и добавьте app:headerLayout="@layout/my_header_layout"
в NavigationView.
colorPrimary
цвет использует цвет, определенный с помощью атрибута colorPrimary
textColorPrimary
textColorSecondary
Вы также можете проверить пример приложения Chris Banes, который выделяет NavigationView вместе с другими новыми представлениями, которые входят в библиотеку поддержки дизайна (например, FloatingActionButton , TextInputLayout , Snackbar , TabLayout и т. Д.),
Заставьте это работать, в значениях – стили v21 или тема xml должны использовать этот атрибут:
<item name="android:windowTranslucentStatus">true</item>
Это делает волшебство!
Все вышеперечисленные подходы являются правильными и могут работать. Я создал рабочую демонстрацию, следуя приведенному выше руководству, и протестировал ее на 2.x до 5.x
Вы можете клонировать из Github
Главное, что нужно сыграть в главной деятельности
toolbar = (Toolbar) findViewById(R.id.toolbar); res = this.getResources(); this.setSupportActionBar(toolbar); ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeButtonEnabled(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ScrimInsetsFrameLayout scrimInsetsFrameLayout = (ScrimInsetsFrameLayout) findViewById(R.id.linearLayout); scrimInsetsFrameLayout.setOnInsetsCallback(this); }
И обратный вызов
@Override public void onInsetsChanged(Rect insets) { Toolbar toolbar = this.toolbar; ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); lp.topMargin = insets.top; int top = insets.top; insets.top += toolbar.getHeight(); toolbar.setLayoutParams(lp); insets.top = top; // revert }
Абсолютно Тема для V21 делает волшебство
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- API 21 theme customizations can go here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/accent_material_light</item> <item name="windowActionModeOverlay">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:windowTranslucentStatus">true</item> </style>
И ScrimInsetsFrameLayout
Теперь это стало проще с новой библиотекой поддержки дизайна
compile 'com.android.support:design:22.2.0'
Клон от @Chris Banes https://github.com/chrisbanes/cheesesquare
Все ответы, упомянутые здесь, слишком стары и длительны. Лучшее и короткое решение, которое работает с последним навигационным обзором
@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); } }
Это изменит цвет вашего состояния на прозрачный, когда вы откроете ящик
Теперь, когда вы закрываете ящик, вам нужно снова изменить цвет строки состояния в темное. Таким образом, вы можете сделать это таким образом.
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" />
Я проверил его и полностью его работоспособность. Надеюсь, это поможет кому-то. Это может быть не лучший подход, но он работает плавно и прост в реализации. Отметьте это, если это поможет. Правильное кодирование 🙂
Я использую библиотеку поддержки дизайна. И только с помощью специальной темы я получил прозрачную панель состояния при открытии навигационного ящика.
<style name="NavigationStyle" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/primaryColor</item> <item name="colorPrimaryDark">@color/primaryColorDark</item> <!-- To Make Navigation Drawer Fill Status Bar and become Transparent Too --> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> </style>
Наконец добавьте тему в файл манифеста
<activity ........ ........ android:theme="@style/NavigationStyle"> </activity>
Не забудьте использовать свойство, android:fitsSystemWindows="true"
в "DrawerLayout"
Это самое простое, и это сработало для меня:
В значениях -21:
<resources> <style name="AppTheme" parent="AppTheme.Base"> ... <item name="android:windowTranslucentStatus">true</item> </style> <dimen name="topMargin">25dp</dimen> </resources>
В значениях:
<resources> <dimen name="topMargin">0dp</dimen> </resources>
И установите на свою панель инструментов
android:layout_marginTop="@dimen/topMargin"
Вместо использования ScrimInsetsFrameLayout
… Не проще ли просто добавить представление с фиксированной высотой 24dp
и фоном primaryColor
?
Я понимаю, что это связано с добавлением фиктивного представления в иерархию, но для меня это кажется более чистым.
Я уже пробовал, и он работает хорошо.
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_base_drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- THIS IS THE VIEW I'M TALKING ABOUT... --> <View android:layout_width="match_parent" android:layout_height="24dp" android:background="?attr/colorPrimary" /> <android.support.v7.widget.Toolbar android:id="@+id/activity_base_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="2dp" android:theme="@style/ThemeOverlay.AppCompat.Dark" /> <FrameLayout android:id="@+id/activity_base_content_frame_layout" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <fragment android:id="@+id/activity_base_drawer_fragment" android:name="com.myapp.drawer.ui.DrawerFragment" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:elevation="4dp" tools:layout="@layout/fragment_drawer" /> </android.support.v4.widget.DrawerLayout>
Попробуйте следующее:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/drawer_layout" android:fitsSystemWindows="true"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!--Main layout and ads--> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@+id/ll_main_hero" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> </FrameLayout> <FrameLayout android:id="@+id/ll_ads" android:layout_width="match_parent" android:layout_height="wrap_content"> <View android:layout_width="320dp" android:layout_height="50dp" android:layout_gravity="center" android:background="#ff00ff" /> </FrameLayout> </LinearLayout> <!--Toolbar--> <android.support.v7.widget.Toolbar android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/toolbar" android:elevation="4dp" /> </FrameLayout> <!--left--> <ListView android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" android:divider="@null" android:background="@mipmap/layer_image" android:id="@+id/left_drawer"></ListView> <!--right--> <FrameLayout android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="right" android:background="@mipmap/layer_image"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@mipmap/ken2" android:scaleType="centerCrop" /> </FrameLayout>
стиль :
<style name="ts_theme_overlay" parent="Theme.AppCompat.Light.NoActionBar"> <item name="colorPrimary">@color/red_A700</item> <item name="colorPrimaryDark">@color/red1</item> <item name="android:windowBackground">@color/blue_A400</item> </style>
Основная деятельность расширяет ActionBarActivity
toolBar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolBar);
Теперь вы можете onCreateOptionsMenu
как обычный ActionBar с ToolBar.
Это мой макет
Надеюсь, ты поймешь!