android пример - Как использовать DrawerLayout для отображения на панели ActionBar / Toolbar и в строке состояния?




что navigation (9)

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


Answers

Новая функциональность в рамках и поддержка libs позволяют именно это. Есть три «кусочка головоломки»:

  1. Использование Toolbar чтобы вы могли встроить панель действий в свою иерархию представлений.
  2. Создание DrawerLayout fitsSystemWindows так, что оно fitsSystemWindows за системные панели.
  3. Отключение Theme.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 (rev 22.2.0) у нас есть библиотека поддержки дизайна и как часть этого нового представления под названием NavigationView . Поэтому вместо того, чтобы делать все самостоятельно с помощью ScrimInsetsFrameLayout и всего остального, мы просто используем это представление, и все делается для нас.

пример

Шаг 1

Добавьте Design Support Library в файл build.gradle

dependencies {
    // Other dependencies like appcompat
    compile 'com.android.support:design:22.2.0'
}

Шаг 2

Добавьте 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>

Шаг 3

Создайте новый меню-ресурс в /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>

Шаг 4

Начните навигацию и обработайте события 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;
            }
        });
    }
}

Шаг 5

Обязательно установите 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 и т. Д.),


Это самое простое, и это сработало для меня:

В значениях -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"

Заставьте это работать, в значениях - стили v21 или тема xml должны использовать этот атрибут:

<item name="android:windowTranslucentStatus">true</item>

Это делает волшебство!


Попробуйте следующее:

<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.

Это мой макет

  • TOP: левый ящик - правый ящик
    • MID: ToolBar (ActionBar)
    • BOTTOM: ListFragment

Надеюсь, ты поймешь!


Все ответы, упомянутые здесь, слишком стары и длительны. Лучшее и короткое решение, которое работает с последним навигационным обзором

@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"
        />

Я тестировал его и полностью работал. Надеюсь, это поможет кому-то. Это может быть не лучший подход, но он работает плавно и прост в реализации. Отметьте это, если это поможет. Правильное кодирование :)


Все вышеперечисленные подходы являются правильными и могут работать. Я создал рабочую демонстрацию, следуя приведенному выше руководству, и протестировал ее на 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


Вместо использования 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>

Фон вашего бара состояния белый, фон вашего ящика LinearLayout . Зачем? У вас есть настройки fitsSystemWindows="true" для вашего DrawerLayout и LinearLayout внутри него. Это приведет к тому, что LinearLayout будет расширяться за панель состояния (прозрачная). Таким образом, сделайте фон для элемента ящика панели состояния белым.


Если вы не хотите, чтобы ваш ящик расширялся за панель состояния (хотите иметь полупрозрачный фон для всей строки состояния), вы можете сделать две вещи:

1) Вы можете просто удалить любое фоновое значение из вашего LinearLayout и покрасить фон вашего содержимого внутри него. Или

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


Если вы хотите, чтобы ваш выдвижной ящик расширялся за панель состояния и имел полупрозрачный оверлей с размером строки состояния, вы можете использовать ScrimInsetFrameLayout в качестве контейнера для содержимого вашего ящика ( ListView ) и установить фон строки состояния с помощью app:insetForeground="#4000" . Конечно, вы можете изменить #4000 на все, что захотите. Не забудьте сохранить fitsSystemWindows="true" здесь!

Или, если вы не хотите накладывать свой контент и показывать только сплошной цвет, вы можете просто установить фон LinearLayout на все, что хотите. Не забудьте установить фон вашего контента отдельно!

EDIT: вам больше не нужно иметь дело с этим. Пожалуйста, см. Библиотеку поддержки дизайна в удобное для пользователя время.







android navigation-drawer appcompat