下面几个是需要用到的依赖库
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support:design:26.+'
compile 'de.hdodenhof:circleimageview:2.1.0'//圆形头像依赖库
compile 'com.android.support:recyclerview-v7:26.+'
compile 'com.android.support:cardview-v7:26.+'
compile 'com.github.bumptech.glide:glide:3.7.0'//图片加载依赖库
一.ToolBar
* android.support.v7.widget.Toolbar, Toolbar继承Actionbar
* Toolbar和ActionBar类似,不过Actionbar由于设计的原因只能位于活动的顶部,而不能实现一些materialdesign效果
而且灵活性很好,可以配合其他控件完成一些materialdesign效果
* 1.因为默认主题都继承Theme.AppCompat.Light.DarkActionBar,如果我们需要使用Toolbar替换Actionbar,主题须使用无Actionbar的Theme.AppCompat.Light.NoActionBar
在xml中使用toolbar,代码如下:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways|snap"//由于5.0之前没有此属性,所以使用app进行兼容
>
在java代码中使用toolbar,代码如下:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);//替换Actionbar
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.setDisplayHomeAsUpEnabled(true);//启用返回键
actionBar.setHomeAsUpIndicator(android.R.drawable.ic_menu_add);//设置返回键图标
}
<activity
android:name=".MainActivity"
android:label="Fruits">//用于显示在ActionBar上的文字,如果没有指定,默认使用Application的
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
????只有一个标题的Toolbar看起来很单调,我们可以再添加一些action按钮来丰富一下,我们可以准备几张图标放在drawable-xxhdpi目录下,然后在res目录新建menu目录,目录下新建一个toolbar.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!--toolbar action按钮只会显示图标,菜单中的action按钮只会显示文字-->
<item
android:id="@+id/backup"
android:icon="@drawable/tab_audior_player01"
android:title="Backup"
app:showAsAction="always">//总是显示toolbar中
</item>
<item android:id="@+id/delete"
android:icon="@drawable/tab_btn_classification_hov"
android:title="Delete"
app:showAsAction="ifRoom"></item>//如果有空间显示在toolbar中
<item android:id="@+id/settings"
android:icon="@drawable/tab_btn_mine_hov"
android:title="Settings"
app:showAsAction="never"></item>//永远显示在菜单中
</menu>
然后我们再Activity中重写两个方法,onCreateOptionMenu用于加载菜单资源,onOptionItemSelected对于菜单点击事件的处理,代码如下:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.backup:
showTips("backup");
break;
case R.id.settings:
showTips("settings");
break;
case R.id.delete:
showTips("delete");
break;
case android.R.id.home:
if(drawerLayout != null){
drawerLayout.openDrawer(GravityCompat.START);
}
break;
}
return true;
}
二、滑动菜单
所谓的滑动菜单就是将一些菜单选项隐藏起来,而不是放在主屏幕上,然后通过滑动的方式将菜单显示出来,这种方式可以节省空间,同时也实现很好的滑动效果,是materialDesign中推荐的做法。
首先它是一个布局,在布局中允许放入两个直接子控件,第一个显示屏幕中显示内容,第二个显示滑动菜单显示的内容,activity_main.xml中的代码如下:
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/drawer_layout"
>
<FrameLayout
android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_navigation_drawer"
app:menu="@menu/activity_navigation_drawer_drawer" />
</android.support.v4.widget.DrawerLayout>
nav_header_navigation_drawer.xml文件如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<!--<ImageView-->
<!--android:id="@+id/imageView"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:paddingTop="@dimen/nav_header_vertical_spacing"-->
<!--app:srcCompat="@android:drawable/sym_def_app_icon" />-->
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:src="@android:drawable/sym_def_app_icon" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="Android Studio"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="android.studio@android.com" />
</LinearLayout>
activity_navigation_drawer_drawer布局文件如下:
<?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/nav_camera"
android:icon="@drawable/ic_menu_camera"
android:title="Import" />
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="Gallery" />
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_menu_slideshow"
android:title="Slideshow" />
<item
android:id="@+id/nav_manage"
android:icon="@drawable/ic_menu_manage"
android:title="Tools" />
</group>
<item android:title="Communicate">
<menu>
<item
android:id="@+id/nav_share"
android:icon="@drawable/ic_menu_share"
android:title="Share" />
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_menu_send"
android:title="Send" />
</menu>
</item>
</menu>

这里最外层的控件是Drawerlayout,这个控件由support-v4提供,Navigationview控件中,layout_gravity这个属性必须指定,因为我们要告诉Drawerlayout是屏幕的左边还是右边,left表示左边,right表示右边,指定start会根据系统语言来判定,然后运行,右滑显示,左滑关闭
????我们只有在左边缘滑动才有效,很多用户根本不知道这个功能,我们怎么提示他们呢?答案:左边加入一个导航按钮
点击按钮滑动菜单显示,代码如下:
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//// TODO: 2018/5/9 2.设置返回键
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(android.R.drawable.ic_menu_add);//设置导航图标
}
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setCheckedItem(R.id.nav_camera);//将此菜单默认选中
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {//可以处理菜单栏中各个菜单的点击事件
drawerLayout.closeDrawers();//关闭所有当前打开的navigation
return true;
}
});
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home://导航按钮点击显示滑动菜单
if(drawerLayout != null){
drawerLayout.openDrawer(GravityCompat.START);
}
break;
}
return true;
}
三、悬浮按钮和交互提示
我们知道toast是一个提示工具,但是只能提示,我们却无法对它进行任何操作,现在我们介绍FloatingActionButton是design support库中提供的一个控件。
布局文件中的使用如下:
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_menu_manage"
android:elevation="16dp"
/>
其中android:layout_gravity设置显示的位置,bottom|end表示显示在右下角,android:elevation表示设置高度,高度值越大投影范围大,但投影效果越淡,高度越小,范围小,但是效果浓。接着我们再java代码中获取FloatingActionbutton对象,代码如下:
floatingActionButton = (FloatingActionButton) findViewById(R.id.fab);
floatingActionButton.setOnClickListener(new View.OnClickListener() {//跟button设置点击没什么两样
@Override
public void onClick(View v) {//Snakbar
// Toast.makeText(MainActivity.this,"hello",Toast.LENGTH_SHORT).show();
Snackbar.make(v,"hello",Snackbar.LENGTH_SHORT).setAction("undo", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"hello hello hello",Toast.LENGTH_SHORT).show();
}
}).show();
}
});
SnackBar允许提示中加入一个可交互的按钮,当用户点击按钮的时候可以执行一些额外的操作,例如用户不小心删除一个非常重要的文件,如果使用snackbar就可以加入按钮,可以避免误操作这种情况。make第一参数传入view,只要是当前页面的任何一个view都可以,snackbar会使用这个view自动查找最外层的布局用于展示snackbar,第二个参数是显示的内容,第三个显示的时长,这个和Toast几乎一样,然后setAction设置一个动作,第一个参数动作显示的文字,第二个参数是点击undo的监听
???不过你发现一个bug没有,Snackbar尽然将我们的floatingActionbutton挡住了,这个时候需要借助CoordinatorLayout解决
四、CoordinatorLayout的使用
其实Coordinator是一个加强版的frameLayout,这个布局也是design support提供,它和framelayout基本一致,不过既然是Design support提供的布局,自然有更强大的用处。
事实上,coordinatorLayout可以监听其所有子控件的各种操作,然后自动帮助我们做出最为合理的响应,举个例子:刚才弹出的Snackbar提示将悬浮窗遮住了,如果我们能让coordinatorLayout监听到Snackbar的弹出事件,我们就会自动将内部的FloatingActionButton向上偏移,从而不会被snackbar遮挡住。布局文件如下:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways|snap"
>
</android.support.v7.widget.Toolbar>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_menu_manage"
android:elevation="16dp"
/>
</android.support.design.widget.CoordinatorLayout>
CoordinatorLayout其实是一个加强版的frameLayout,所以替换framelayout没有一点问题。可以看到,悬浮窗按钮自动向上偏移snackbar的高度,消失的时候自动向下偏移回到原来位置
???刚才说了coordinatorLayout可以监听所有子控件的各种事件,但是snackbar好像并不是coordinatorLayout子控件,为什么它却可以监听???其实道理很简单,Snackbar的make第一个参数传入的view用于指定Snackbar是基于那个view触发的,刚才我们传入的是FloatingActionButton本身,而FloatingActionButton是coordinaorLayout的子控件,因此这个事件理所让然被监控到。
五、卡片式布局
CardView是用于卡片式布局的重要控件,有appcompat-v7库提供,其实cardview也是一个framelayout,只是额外提供了圆角和yin影效果,看上去有立体的感觉。
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardCornerRadius="@dimen/fab_margin"
app:cardElevation="@dimen/fab_margin">
}
app:cardcornerRadius指定圆角的角度,app:elevation指定高度
以下这段代码,由于coordinatorLayout的增强版的FrameLayout布局,所以很显然RecyclerView会把Toolbar给挡住,这个问题怎么解决呢?这就需要借助另外一个工具--APPBarLayout
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
>
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</android.support.v7.widget.RecyclerView>
</android.support.design.widget.CoordinatorLayout>
六、AppBarLayout
AppBarLayout其实是一个垂直方向上的LinearLayout,它的内部做了很多滚动事件的封装,并应用一些MaterialDesign的设计理念。那怎么使用AppBarLayout才能解决上面的问题呢?第一步将ToolBar嵌套到AppBarLayout中,第二部给RecyclerView指定一个布局行为,修改activity_main.xml中的代码,如下所示:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</android.support.design.widget.CoordinatorLayout>
可以看到,布局文件没有太大的变化,我们首先定义了一个AppBarLayout,并将ToolBar放置在AppBarLayout里面,然后在RecyclerView中使用app:layout_behavior属性指定一个行为,其中appbar_scrolling_view_behavior这个字符串也是由Design support库提供的,运行一下已经成功解决了toolbar被recyclerview遮挡的问题,但是AppBarLayout应用了materialDesign的理念,好像从上面的例子并不能体现出来,事实上当RecyclerView滚动的时候已经将滚动事件通知给了AppBarLayout,只不过我们还没进行处理,接下来我们来进一步优化。
当AppBarLayout接收到滚动的时候,它的内部的子控件其实是可以指定如何影响这些事件的,通过app:layout_scrollFlags属性就可以实现,修改这面的代码,只需要在Toolbar中加入app:layout_scrollFlags,代码如下:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
这个属性指定了app:layout_scrollFlags属性,并将这个属性指定为scroll|enterAlways|snap。其中scroll表示RecyclerView向上滚动的时候,toolbar会跟着一起向上并隐藏;enterAlways表示RecyclerView向下滚动的时候,Toolbar会跟着一下向下滚动并重新显示,Snap表示Toolbar还没有完全隐藏或显示的时候,会根据当前的距离自动隐藏或显示。七、下拉刷新
SwipeRefreshLayout就是用于实现下拉刷新功能的核心类,它是support-v4库提供的,我们想要下拉刷新功能的控件直接放在SwipeRefreshLayout中,就可以迅速让这个控件支持下拉刷新,代码如下:
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
可以看到,我们在RecyclerView的外面潜逃了一层SwipeRefreshLayout,这样RecyclerView就自动拥有下拉刷新功能了,另外需要注意,由于RecyclerView现在变成了SwipeRefreshLayout的子控件,因此之前使用app:layout_behavior声明的布局行为现在要放到SwipeRefreshLayout中。
不过这还没有结束,虽然我们在布局中已经支持下拉刷新功能,但是我们还需要在代码中处理刷新逻辑才行,修改MainActivity的代码如下:
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_layout);
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary,R.color.colorAccent,R.color.colorPrimaryDark);//设置进度条颜色
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {//设置刷新监听
@Override
public void onRefresh() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
initFruits();
fruitAdapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);//刷新完成,因此进度条
}
});
}
}).start();
}
});
八、可折叠式标题栏
虽说我们现在的标题栏是使用Toolbar来写的,但是看上去和传统的Actionbar其实没什么区别,只不过可以相应RecyclerView的滚动事件来隐藏和显示,而MaterialDesign并没有限制标题栏必须长这样,事实上,我们可以根据自己的喜好随意定制标题栏的样式,所以我们需要借助CollapsingToolbarLayout这个工具。
CollapsingToolbarLayout
顾名思义,CollapsingToolbarLayout是一个作用于Toolbar基础之上的布局,它也是由Design support库提供的,CollapsingTollbarLayout可以让Toolbar的效果变得更加丰富,不仅仅是展示一个标题栏,而是非常绚丽的效果。
不过,CollapsingToolbarLayout是不能独立存在的,它在设计的时候就被限定只能作为AppBarLayout的直接子类来使用,而AppBarLayout又必须是CoordinatorLayout的子布局。
<android.support.design.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.richard.materialdesign.FruitDetailActivity"
>
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="250dp"
>
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collaplayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="@color/colorPrimaryDark"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
/>
这里使用了CollapsingToolbarLayout,android:theme属性指定一个主题,因为之前在toolbar中也指定了这个主题,只不过这里讲属性提到toolbar的更高一级CollapsingToolbarLayout中,app:contentScrim属性指定CollapsingToolbarLayout在趋于折叠状态之后的背景色,其实CollapsingToolbarLayout折叠之后就是一个普通的Toolbar,app:layout_scrollFlags属性中scroll表示CollapsingToolbarLayout随着一起滚动,exitUntilCollapsed表示当CollapsingToolbarLayout随着滚动完成折叠之后保留在界面上,不再移除屏幕,在CollapsingToolbarLayout中加入以下代码:
<ImageView
android:id="@+id/fruit_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
></android.support.v7.widget.Toolbar>
可以看到CollapsingToolbarLayout中定义了一个imgeview和一个Toolbar,也就意味着高级标题栏由一个普通的标题栏加上图片组合而成的,这里定义的大多属性我们都见过,就不再解释,只有一个app:layout_collapseMode比较陌生,它用于指定当前控件在CollapsingToolbarLayout折叠过程中的折叠模式,其中Toolbar指定成pin,表示折叠的过程中位置始终保持不变,ImageView指定成parallax,表示折叠的过程中产生一定的错位偏移,这是模式的视觉效果会非常好。在AppBarLayout的平级位置加入以下代码:
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
我们知道scrollview允许使用滚动查看屏幕以外的数据,而NestedScrollView在此基础上海增加了嵌套相应滚动事件的功能,由于CoordinatorLayout本身可以相应滚动事件了,因此我们在它内部就需要使用NestedScrollView或RecyclerView这样的布局,另外我们还通过app:layout_behavior属性指定一个布局行为,这和之前的RecyclerView中的用法一模一样的。
不管Scrollview还是NestedScrollView,它们内部都只允许存在一个直接子布局,因此我们如果想要放入很多东西的话,通常都会嵌套一个LinearLayout,然后在放入具体的内容,内容如下:
<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
android:layout_marginBottom="35dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/fruit_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"/>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
最后我们在页面放入一个悬浮窗,它和AppBarLayout和NestedScrollView是平级的,如下所示:
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"
android:layout_margin="@dimen/activity_horizontal_margin"
android:src="@drawable/tab_audior_player01"/>
app:layout_anchor属性指定了一个锚点,而我们将锚点设置为AppBarLayout,这样悬浮按钮就会出现在AppBarLayout的区域内,CollapsingToolbarlayout的setTitle()方法设置标题
充分利用系统状态栏空间
你会发现图片背景和状态栏的背景不搭的感觉,如果背景和状态栏颜色融合一起,那视觉体验绝对上升一个层次。
只不过5.0系统之前我们无法对状态栏的背景或者颜色进行操作,但是5.0及之后都是支持这个功能,因此我们可以实现一个系统差异性的效果,在5.0及之后使用背景和状态栏融合,5.0之前使用普通的模式。
想要背景图和状态栏融合,需要借助android:fitsSystemWindows这个属性来实现,在coordinatorlayout,AppBarLayout,CollapsingToolbarlayout这种嵌套结构的布局中,将控件的android:fitssystemWindows属性指定true,就表示该控件会出现在系统状态栏中。对应我们的程序,就是Imageview设置成这个属性,只不过设置这个属性是没有用的,我们必须将iamgeview布局结构中的所有父容器都设置上这个属性才可以,代码如下;
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.richard.materialdesign.FruitDetailActivity"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collaplayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="@color/colorPrimaryDark"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
android:fitsSystemWindows="true"
>
<LinearLayout
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_collapseMode="parallax"
android:fitsSystemWindows="true"
android:orientation="vertical"
>
<android.support.v7.widget.SearchView
android:id="@+id/search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="热门电影红海行动"
android:textColorHint="@android:color/white"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:autofillHints="热门电影红海行动"
android:layout_marginTop="80dp"
android:background="@color/colorPrimary"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="30dp">
<ImageButton
android:id="@+id/ib1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_audior_player01"
android:background="@null"
android:layout_weight="1"
/>
<ImageButton
android:id="@+id/ib2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_audior_player02"
android:background="@android:color/transparent"
android:layout_weight="1"
/>
<ImageButton
android:id="@+id/ib3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_audior_player03"
android:background="@null"
android:layout_weight="1"
/>
<ImageButton
android:id="@+id/ib4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tab_audior_player04"
android:background="@null"
android:layout_weight="1"
/>
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/fruit_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
android:fitsSystemWindows="true"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
></android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
android:layout_marginBottom="35dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/fruit_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/activity_horizontal_margin"/>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"
android:layout_margin="0dp"
android:src="@drawable/tab_audior_player01"/>
</android.support.design.widget.CoordinatorLayout>
即使这样还是没有用,因为我们必须在程序的主题中将状态栏颜色指定成透明色才行。指定成透明的方法很简单,在主题中android:statusBarColor属性值指定成@android:color/transparent就可以了,但是这个属性只有api21才有的,之前没有这个属性,那么系统差异的功能就从这里开始。
新建values-v21文件夹,然后新建style.xml文件,接着编写文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="fruitActivityTheme" parent="AppTheme">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
但是如果是这样,5.0之前没有定义这个样式就会报错,所以我们在values下style.xml中定义一个没有指定状态栏颜色的样式:
<style name="fruitActivityTheme" parent="AppTheme">