Translucent System Bars-4.4新特性
NavigationDrawer 简介
NavigationDrawer 是 Google 在 Material Design 中推出的一种侧滑导航栏设计风格。说起来很抽象,我们来看下网易云音乐侧滑导航栏的实现效果
想有漂亮的 Material Design,Google 已提供 Android Design Support Library 可供使用。它支援 Android 2.1 或以上,提供不少好用的 UI element,可方便做到 Material Design Pattern 的效果。
为了实现这种效果,Google官方推出一个新控件 —— DrawerLayout 。而在 DrawerLayout 没诞生之前,需求中需要实现侧滑导航效果时,我们通常会选择去选择一些成熟的第三方开源库(如最有名的 SlidingMenu)来实现类似的效果。
既然官方有提供,我们为何不使用呢? 不用引入第三方的jar,避免65536(你懂得),还能减少APP的体积,关键是使用起来简单,何乐而不为之呢?
DrawerLayout基本使用
英文666的童鞋可以查看这里How To Make Material Design Navigation Drawer With Header View
一般情况下,在DrawerLayout布局下只会存在两个子布局:
- 内容布局
- 侧滑菜单布局
这两个布局的关键在于 android:layout_gravity属性的设置。
如果你把其中一个子布局设置成了左侧滑菜单,只需要设置 android:layout_gravity=”start” 即可(也可以是left, 右侧滑为end或者right)。
没有设置的布局 自然成为了 内容布局
对,就这么简单…..按照常规,先上效果图,然后上code
效果图
Code
activity_naviation_drawer_base_use.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.widget.DrawerLayout android:id="@+id/simple_navigation_drawer" android:layout_width="match_parent" android:layout_height="match_parent"> <!--内容视图--> <include android:id="@+id/tv_content" layout="@layout/drawer_content_layout" android:layout_width="match_parent" android:layout_height="match_parent" /> <!--左侧滑菜单栏--> <include layout="@layout/drawer_menu_layout" android:layout_width="250dp" android:layout_height="match_parent" android:layout_gravity="start" /> <!--右侧滑菜单栏--> <include layout="@layout/drawer_menu_layout" android:layout_width="250dp" android:layout_height="match_parent" android:layout_gravity="end" /> </android.support.v4.widget.DrawerLayout> </RelativeLayout>
drawer_content_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:gravity="center_vertical" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="setScrimColor: " /> <RadioGroup android:id="@+id/rg_scrim_color" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <RadioButton android:id="@+id/rbtn_pink" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@mipmap/pink" /> <RadioButton android:id="@+id/rbtn_green" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@mipmap/green" /> <RadioButton android:id="@+id/rbtn_blue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@mipmap/blue" /> </RadioGroup> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:gravity="center_vertical" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="openDrawer: " /> <RadioGroup android:id="@+id/rg_open_drawer" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <RadioButton android:id="@+id/rbtn_from_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="left | start" /> <RadioButton android:id="@+id/rbtn_from_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="right | end" /> </RadioGroup> </LinearLayout> </LinearLayout>
drawer_menu_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="250dp" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color_f5f5f5" android:gravity="center" android:text="@string/simple_navigation_drawer" /> </LinearLayout>
NaviationDrawerBaseUseAct.java
package com.turing.navigationdrawer; import android.os.Bundle; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.view.Gravity; import android.view.View; import android.widget.RadioGroup; import android.widget.Toast; public class NaviationDrawerBaseUseAct extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener{ private DrawerLayout drawerLayout ; private RadioGroup rg_setScrimColor ,rg_openDrawer ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_naviation_drawer_base_use); initView(); initEvents(); } private void initView() { //DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.simple_navigation_drawer); //RadioGroup rg_setScrimColor = (RadioGroup) findViewById(R.id.rg_scrim_color); rg_openDrawer = (RadioGroup) findViewById(R.id.rg_open_drawer); } private void initEvents() { //监听DrawerLayout的侧滑 drawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() { @Override public void onDrawerSlide(View drawerView, float slideOffset) { } @Override public void onDrawerOpened(View drawerView) { Toast.makeText(NaviationDrawerBaseUseAct.this, "onDrawerOpened", Toast.LENGTH_SHORT).show(); } @Override public void onDrawerClosed(View drawerView) { Toast.makeText(NaviationDrawerBaseUseAct.this, "onDrawerClosed", Toast.LENGTH_SHORT).show(); } @Override public void onDrawerStateChanged(int newState) { } }); // RadioGroup 监听事件 rg_setScrimColor.setOnCheckedChangeListener(this); rg_openDrawer.setOnCheckedChangeListener(this); } /** * RadioButton被选中后的操作 * @param group * @param checkedId */ @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId){ case R.id.rbtn_pink: drawerLayout.setScrimColor(getResources().getColor(R.color.color_e81d62)); break; case R.id.rbtn_green: drawerLayout.setScrimColor(getResources().getColor(R.color.color_4bae4f)); break; case R.id.rbtn_blue: drawerLayout.setScrimColor(getResources().getColor(R.color.color_2095f2)); break; case R.id.rbtn_from_left: drawerLayout.openDrawer(Gravity.LEFT);//打开菜单栏 break; case R.id.rbtn_from_right: drawerLayout.openDrawer(Gravity.RIGHT); break; default: break; } } }
注意事项
DrawerLayout 为 v4包中的 android.support.v4.widget.DrawerLayout
DrawerLayout的监听事件 new DrawerLayout.DrawerListener(){…}
Google为我们提供了DrawerLayout常用的API,比如打开或者关闭侧滑栏、控制侧滑栏的方向、设置滑动时渐变的阴影颜色和监听滑动事件等,详见官方API
DrawerLayout 中的android:layout_width需要设置成match_parent,不能设置成wrap_content,否则会抛出 DrawerLayout must be measured with MeasureSpec.EXACTLY error
-
效果图
NavigationView
官方文档
Represents a standard navigation menu for application. The menu contents can be populated by a menu resource file.
NavigationView is typically placed inside a 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"> <!-- 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/my_navigation_items" /> </android.support.v4.widget.DrawerLayout>
概述
在Google推出NavigationDrawer设计中,NavigationView和DrawerLayout是官方推荐的最佳组合。
NavigationView是一个导航菜单框架,使用menu资源填充数据,使我们可以更简单高效的实现导航菜单。它提供了不错的默认样式、选中项高亮、分组单选、分组子标题、以及可选的Header.
在使用NavigationView之前,因为它Android Design Support Library(Material Design的兼容包)中,所以我们需要在build.gradle中加入 compile ‘com.android.support:design:23.1.1’
apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { applicationId "com.turing.navigationdrawer" minSdkVersion 10 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:design:23.1.1' }
引用注意事项:
工程配置的 compileSdkVersion 是 23 ,所以需要引入 com.android.support:design:23.x.x 的版本。需要吐槽的是,这里如果你引入了 com.android.support:design:23.1.0 ,工程运行后 NavigationView 会报一个 android.view.InflateException:xxxxxx 的错误
运行效果
Code
最主要的两个属性分别是:
app:headerLayout接收一个layout,作为导航菜单顶部的Header,可选项。
app:menu接收一个menu,作为导航菜单的菜单项,几乎是必选项,不然这个控件就失去意义了。但也可以在运行时动态改变menu属性。
用于NavigationView的典型menu文件,应该是一个可选中菜单项的集合。其中checked=”true”的item将会高亮显示,这可以确保用户知道当前选中的菜单项是哪个。item的选中状态也可以在代码中设置。
activity_navigation_view_base_use.xml
<?xml version="1.0" encoding="utf-8"?> <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" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color_31c27c"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="NavigationDrawerContent" /> </LinearLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/navigation_drawer_header" app:menu="@menu/navigation_drawer_menu" /> </android.support.v4.widget.DrawerLayout>
navigation_drawer_header.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="250dp" android:background="@color/color_512da8"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_margin="10dp" android:text="HeaderLayout" android:textColor="@android:color/white" android:textSize="18sp" /> </RelativeLayout>
menu/navigation_drawer_menu.xml
在menu目录下
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/item_green" android:icon="@mipmap/green" android:title="Green" /> <item android:id="@+id/item_blue" android:icon="@mipmap/blue" android:title="Blue" /> <item android:id="@+id/item_pink" android:icon="@mipmap/pink" android:title="Pink" /> </group> <item android:title="SubItems"> <menu> <item android:id="@+id/subitem_01" android:icon="@mipmap/ic_launcher" android:title="SubItem01" /> <item android:id="@+id/subitem_02" android:icon="@mipmap/ic_launcher" android:title="SubItem02" /> <item android:id="@+id/subitem_03" android:icon="@mipmap/ic_launcher" android:title="SubItem03" /> </menu> </item> <item android:title="SubItems"> <menu> <item android:id="@+id/subitem_04" android:icon="@mipmap/ic_launcher" android:title="SubItem04" /> <item android:id="@+id/subitem_05" android:icon="@mipmap/ic_launcher" android:title="SubItem05" /> <item android:id="@+id/subitem_06" android:icon="@mipmap/ic_launcher" android:title="SubItem06" /> </menu> </item> </menu>
NavigationViewBaseUseAct.java
package com.turing.navigationdrawer; import android.os.Bundle; import android.support.design.widget.NavigationView; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.Window; import android.widget.Toast; public class NavigationViewBaseUseAct extends AppCompatActivity { private DrawerLayout drawerLayout; private NavigationView navigationView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_navigation_view_base_use); drawerLayout = (DrawerLayout) findViewById(R.id.drawer); navigationView = (NavigationView) findViewById(R.id.navigation_view); //设置菜单图标恢复本来的颜色,不设置的话 是没有颜色的...... navigationView.setItemIconTintList(null); // 设置监听事件 navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.subitem_01: Toast.makeText(NavigationViewBaseUseAct.this, "sub item 01", Toast.LENGTH_SHORT).show(); break; default: break; } // 关闭drawerlayout drawerLayout.closeDrawers(); return true; } }); } }
注意事项:
-第一次运行代码的时候,图标的颜色居然都是灰色的….代码中可以调用下面这个APInavigationView.setItemIconTintList(null);//设置菜单图标恢复本来的颜色
- NavigationView 基本已经规定设置好了大小距离,留给我们可以改动的空间并不多。详见官方文档(自备梯子)如果你想调整一下菜单的布局宽高之类的,基本是不可能的了
仿网易云音乐的 NavigationDrawer 实现
官方运行图
里面的图标,可以下载APP,解压后,去文件夹里取出来~
主要就是一个线性布局的菜单并结合了 Translucent System Bar 的特性。
Code
activity_cloud_music.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color_cd3e3a"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="65dp" android:background="@color/color_cd3e3a" android:gravity="center" android:text="网易云音乐" android:textColor="@android:color/white" android:textSize="18sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:orientation="vertical"> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/navigation_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start" android:background="@android:color/white" android:fitsSystemWindows="true" android:orientation="vertical" > <ImageView android:layout_width="match_parent" android:layout_height="180dp" android:scaleType="centerCrop" android:src="@mipmap/topinfo_ban_bg" /> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:src="@mipmap/topmenu_icn_msg" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我的消息" android:textColor="@android:color/black" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:src="@mipmap/topmenu_icn_store" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="积分商城" android:textColor="@android:color/black" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:src="@mipmap/topmenu_icn_member" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="付费音乐包" android:textColor="@android:color/black" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:src="@mipmap/topmenu_icn_free" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="在线听歌免流量" android:textColor="@android:color/black" android:textSize="15sp" /> </LinearLayout> </LinearLayout> </android.support.v4.widget.DrawerLayout>
沉浸式主题样式,需要在不同SDK的values目录下,设置样式,在Manifest.xml中通过 android:theme引用主题,别忘了 android:fitsSystemWindows=”true”。
效果图
左上角的导航动画效果实现
效果
ActionBarDrawerToggle实现
之前想要引入这种效果,都是来自第三方的开源代码,诸如下面两个比较有名的:
自从MaterialDesign出来之后,就再也需要了,Google提供了ActionBarDrawerToggle
activity_animation_left_top.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="@style/Theme.Drawer.ArrowAnimation" /> <android.support.v4.widget.DrawerLayout android:id="@+id/drawer" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="NavigationAnimation" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start" android:background="@android:color/white" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Drawer" /> </LinearLayout> </android.support.v4.widget.DrawerLayout> </LinearLayout>
AnimationLeftTopAct.java
package com.turing.navigationdrawer; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.view.Window; public class AnimationLeftTopAct extends AppCompatActivity { private Toolbar mToolbar; private DrawerLayout mDrawerLayout; private ActionBarDrawerToggle mActionBarDrawerToggle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_animation_left_top); mToolbar = (Toolbar) findViewById(R.id.toolbar); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer); mActionBarDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.open, R.string.close); mDrawerLayout.setDrawerListener(mActionBarDrawerToggle); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mActionBarDrawerToggle.syncState(); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (mActionBarDrawerToggle.onOptionsItemSelected(item)) { return true; } return super.onOptionsItemSelected(item); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mActionBarDrawerToggle.onConfigurationChanged(newConfig); } }
material-menu 开源的动画效果
比 NavigationView 更好的选择
参考文章:http://www.jianshu.com/p/c8cbeb7ea43a#
感谢D_clork