Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件。最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2。
使用Support Library非常简单,添加引用即可:
compile 'com.android.support:design:23.2.0' //可修改版本号为自己匹配
Design Support Library包含8个控件,具体如下:
下面分别详细介绍。
介绍这几个控件之前,我们先来看看Material Design主题的风格。
md的主题有:
与之对应的Compat Theme:
我们可以根据我们的app的风格,去定制Color Palette(调色板),重点有以下几个属性:
<resources>
<!-- Base application theme. -->
<style name="AppBaseTheme" parent="Theme.AppCompat"> <!-- customize the color palette --> <item name="colorPrimary">@color/material_blue_500</item> <item name="colorPrimaryDark">@color/material_blue_700</item> <item name="colorAccent">@color/material_green_A200</item> </style>
</resources>
colorPrimary 对应ActionBar的颜色。
colorPrimaryDark对应状态栏的颜色
colorAccent 对应EditText编辑时、RadioButton选中、CheckBox等选中时的颜色。
注:对于5.0以下的设备,目前colorPrimaryDark无法去个性化状态栏的颜色;底部的navagationBar可能也不一样,更别说设置颜色了。
Snackbar提供了一个介于Toast和AlertDialog之间轻量级控件,它可以很方便的提供消息的提示和动作反馈。Snackbar和Toast比较相似,但是用途更加广泛,并且它是可以和用户进行交互的。Snackbar使用一个动画效果从屏幕的底部弹出来,过一段时间后也会自动消失。
Snackbar.make(snackBar, "Snackbar comes out", Snackbar.LENGTH_LONG)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText( MainActivity.this,"Toast comes out",Toast.LENGTH_SHORT).show();
}
}).show();
这里调用Snackbar的make()方法来创建一个Snackbar对象,make()方法的第一个参数是Snackbar显示的基准元素,需要传入一个view,只要是当前界面布局的任意一个view都可以,Snackbar会使用这个view来自动查找最外层的布局,用于展示Snackbar。第二个参数就是Snackbar中显示的内容,第三个参数是Snackbar显示的时长。这些和Toast都是类似的。
接着这里又调用了一个setAction()方法来设置一个动作,从而让Snackbar不仅仅是一个提示,而是可以和用户进行交互的,这里Action可以设置多个。最后调用show()方法让Snackbar显示出来。
Google API Doc 官方说明:
TextInputLayout功能非常简单,就是用于用户在EditText中输入时hint的提示和错误的提示。
先来看看效果图吧:
从上图很明显的看出:
1、当EditText获得焦点时候,TextInputLayout会在左上角默认生成一个Label用来显示EditText中hint的内容,所以当用户输入时候hint内容会浮动到左上角,这极大便利了用户输入提交数据的体验。
2、当EditText中输入的内容不合法时,TextInputLayout便会在EditText的左下角用红色显示错误的提示信息。
下面来看看怎么用代码实现上面功能吧:
先看看布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" 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">
<Button android:id="@+id/snackBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SnackBar" android:layout_margin="10dp"/>
<android.support.design.widget.TextInputLayout android:id="@+id/til_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp">
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout android:id="@+id/til_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp">
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
在Java代码中实现:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
til_name = (TextInputLayout) findViewById(R.id.til_name);
til_password = (TextInputLayout) findViewById(R.id.til_password);
//设置Hint信息
til_name.setHint("Name");
til_password.setHint("Password");
//设置输入监听
til_name.getEditText().addTextChangedListener(new MyTextWatcher(til_name, "用户名长度不能小于6位"));
til_password.getEditText().addTextChangedListener(new MyTextWatcher(til_password, "密码长度不能小于6位"));
}
//自定义监听器
class MyTextWatcher implements TextWatcher {
private TextInputLayout mTextInputLayout;
private String errorInfo;
public MyTextWatcher(TextInputLayout textInputLayout, String errorInfo) {
this.mTextInputLayout = textInputLayout;
this.errorInfo = errorInfo;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (mTextInputLayout.getEditText().getText().toString().length() < 6) {
mTextInputLayout.setErrorEnabled(true);//打开错误提示
mTextInputLayout.setError(errorInfo);//设置错误提示信息
} else {
mTextInputLayout.setErrorEnabled(false);//关闭错误提示
}
}
}
其中,需要注意以下几点:
1、TextInputLayout布局中只能包含一个EditText子View,不能包含多个EditText。
2、TextInputLayout中有个方法getEditText();该方法返回的是它的子EditText对象,所以我们可通过mTextInputLayout.getEditText();来得到EditText对象,不需要findViewById找了。
3、设置错误提示信息时一定要先setErrorEnabled(true);再设置setError(…);因为TextView只在setErrorEnabled(true)方法中创建,必须创建好TextView才能往TextView上设置信息。而不需要设置时直接setErrorEnabled(false);即可,因为它自身会remove移除TextView。
4、TextInputLayout的颜色来自style中的colorAccent的颜色。
<item name="colorAccent">#FF4081</item>
FloatingActionButton 是一个负责显示界面基本操作的圆形悬浮按钮。FAB继承自ImageView,你可以使用android:src或者ImageView的任意方法,比如setImageDrawable()来设置FloatingActionButton里面的图标。
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:src="@drawable/good"/>
其他设置:
注意:使用以下属性时,需要在Layout中添加命名空间:xmlns:app=”http://schemas.android.com/apk/res-auto”
(1)悬浮操作按钮支持两种size(normal和mini),默认是normal,可以通过app:fabSize指定。
(2)FAB背景颜色默认取的是style中的colorAccent,可以通过app:backgroundTint来指定。
(3)FAB点击时颜色效果默认取的是theme中的colorControlHighlight,可以通过app:rippleColor来指定。
(4)和立体感相关有两个属性,elevation和pressedTranslationZ,前者用户设置正常显示的阴影大小;后者是点击时显示的阴影大小。
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/good"
app:fabSize="mini"
app:backgroundTint="#ff0000ff"
app:rippleColor="#ff00ff00"
app:elevation="6dp"
app:pressedTranslationZ="12dp"/>
通过选项卡的方式切换View并不是MD中才有的新概念,但是Google却是第一次在support库中提供了完整的支持,而且,Design library的TabLayout 既实现了固定的选项卡 (View的宽度平均分配),也实现了可滚动的选项卡(View宽度不固定同时可以横向滚动)。选项卡可以在程序中动态添加:
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@color/colorPrimary"
app:tabTextColor="#ffffffff"
app:tabSelectedTextColor="#ffff0000"
app:tabIndicatorColor="#ffffff00"
app:tabIndicatorHeight="5dp"
app:tabMode="fixed"/>
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.addTab(tabLayout.newTab().setText("tab1"));
tabLayout.addTab(tabLayout.newTab().setText("tab2"));
tabLayout.addTab(tabLayout.newTab().setText("tab3"));
但实际开发中我们很少这样用,通常滑动布局都会和ViewPager配合起来使用,所以,我们需要ViewPager来帮忙:
布局文件:
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@color/colorPrimary"
app:tabTextColor="#ffffffff"
app:tabSelectedTextColor="#ffff0000"
app:tabIndicatorColor="#ffffff00"
app:tabIndicatorHeight="5dp"
app:tabMode="fixed"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Java中设置ViewPager数据,并将ViewPager和TabLayout关联起来。
private void setupViewPager() {
mInflater = LayoutInflater.from(this);
view1 = mInflater.inflate(R.layout.tab_main, null);
view2 = mInflater.inflate(R.layout.tab_main, null);
view3 = mInflater.inflate(R.layout.tab_main, null);
view4 = mInflater.inflate(R.layout.tab_main, null);
view5 = mInflater.inflate(R.layout.tab_main, null);
//添加页卡视图
mViewList.add(view1);
mViewList.add(view2);
mViewList.add(view3);
mViewList.add(view4);
mViewList.add(view5);
//添加页卡标题
mTitleList.add("No:1");
mTitleList.add("No:2");
mTitleList.add("No:3");
mTitleList.add("No:4");
mTitleList.add("No:5");
mTabLayout.setTabMode(TabLayout.MODE_FIXED);//设置tab模式,当前为系统默认模式
mTabLayout.addTab(mTabLayout.newTab().setText(mTitleList.get(0)));
mTabLayout.addTab(mTabLayout.newTab().setText(mTitleList.get(1)));
mTabLayout.addTab(mTabLayout.newTab().setText(mTitleList.get(2)));
mTabLayout.addTab(mTabLayout.newTab().setText(mTitleList.get(3)));
mTabLayout.addTab(mTabLayout.newTab().setText(mTitleList.get(4)));
MyPagerAdapter mAdapter = new MyPagerAdapter(mViewList, mTitleList);
mViewPager.setAdapter(mAdapter);//给ViewPager设置适配器
mTabLayout.setupWithViewPager(mViewPager);//将TabLayout和ViewPager关联起来。
mTabLayout.setTabsFromPagerAdapter(mAdapter);//给Tabs设置适配器
}
ViewPager的Adapter适配器:
class MyPagerAdapter extends PagerAdapter {
private List<View> mViewList;
private List<String> mTitleList;
public MyPagerAdapter(List<View> mViewList, List<String> mTitleList) {
this.mViewList = mViewList;
this.mTitleList = mTitleList;
}
@Override
public int getCount() {
return mViewList.size();//页卡数
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;//官方推荐写法
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mViewList.get(position));//添加页卡
return mViewList.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mViewList.get(position));//删除页卡
}
@Override
public CharSequence getPageTitle(int position) {
return mTitleList.get(position);//页卡标题
}
}
NavigationView在MD设计中非常重要,之前Google也提出了使用DrawerLayout来实现导航抽屉。这次,在support library中,Google提供了NavigationView来实现导航菜单界面,所以,新的导航界面可以这样写了:
<android.support.v4.widget.DrawerLayout android:id="@+id/dl_main_drawer" 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="match_parent" android:fitsSystemWindows="true">
<!-- 你的内容布局-->
<include layout="@layout/content"/>
<android.support.design.widget.NavigationView android:id="@+id/nv_main_navigation" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/navigation_header" app:menu="@menu/drawer_view"/>
</android.support.v4.widget.DrawerLayout>
可以看到我们的最外层是DrawerLayout,里面一个content,一个作为drawer。我们的drawer为NavigationView。
其中NavigationView 中的 android:layout_gravity=”start” 属性来控制抽屉菜单从哪边滑出,一般 “start ”从左边滑出,“end”从右边滑出。
其中最重要的就是下面两个属性:
app:headerLayout
app:menu
通过这两个属性,我们可以非常方便的指定导航界面的头布局和菜单布局。
来看看headerLayout的布局文件(layout目录)和menu配置文件(menu目录):
<?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="200dp" android:background="#ff0000ff" android:gravity="center" android:orientation="vertical" android:padding="16dp" android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView android:layout_width="100dp" android:layout_height="100dp" android:layout_marginTop="16dp" android:background="@drawable/head"/>
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:gravity="center" android:text="Watson" android:textSize="20sp"/>
</LinearLayout>
<?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_home" android:icon="@drawable/setting" android:title="Home"/>
<item android:id="@+id/nav_messages" android:icon="@drawable/setting" android:title="Messages"/>
<item android:id="@+id/nav_friends" android:icon="@drawable/setting" android:title="Friends"/>
<item android:id="@+id/nav_discussion" android:icon="@drawable/setting" android:title="Discussion"/>
</group>
<item android:title="Sub items">
<menu>
<item android:icon="@drawable/star" android:title="Sub item 1"/>
<item android:icon="@drawable/star" android:title="Sub item 2"/>
</menu>
</item>
</menu>
默认的颜色很多是从当前的主题中提取的,比如icon的stateColor,当然你也可以通过以下方法或属性修改部分样式:
你可以通过设置一个OnNavigationItemSelectedListener,使用其setNavigationItemSelectedListener()来获得元素被选中的回调事件。它为你提供被点击的 菜单元素 ,让你可以处理选择事件,改变复选框状态,加载新内容,关闭导航菜单,以及其他任何你想做的操作。例如这样:
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
menuItem.setChecked(true);
mDrawerLayout.closeDrawers();
return true;
}
});
}
同时,为了不遮住导航抽屉,我们选择隐藏ActionBar:
隐藏可以通过修改我们继承的主题为:Theme.AppCompat.Light.NoActionBar,当然也可以通过设置以下属性完成:
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
我们这里选择前者:
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- customize the color palette -->
<item name="colorPrimary">#673AB7</item>
<item name="colorPrimaryDark">#512DA8</item>
<item name="colorAccent">#FF4081</item>
</style>
<application
...
android:theme="@style/AppTheme">
...
</application>
来看看运行效果
效果不错,不过存在一个问题,此时如果你点击Sub items里面的Sub item,发现它一直是选中状态,点击多个Sub item后会出现多个同时选中的情况。那怎么办呢?只能我们来手动切换了:
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
private MenuItem mPreMenuItem;
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
if (mPreMenuItem != null) mPreMenuItem.setChecked(false);
menuItem.setChecked(true);
//关闭抽屉侧滑菜单
mDrawerLayout.closeDrawers();
mPreMenuItem = menuItem;
return true;
}
});
这里我们的导航菜单是通过手势滑动打开的,其实我们也可以通过函数实现:
/**打开抽屉侧滑菜单*/
mDrawerLayout.openDrawer(GravityCompat.START);
众所周知,在使用ActionBar的时候,一堆的问题:位置固定在顶部不能改变,文字不能定制,图标的间距不能控制等等,由此暴露出了ActionBar的设计不够灵活。为此官方提供了ToolBar,并且提供了supprot library用于向下兼容。Toolbar之所以灵活,是因为它其实就是一个ViewGroup,我们在使用的时候和普通的组件一样,在布局文件中声明。下面来看看Toolbar的使用。
首先隐藏原本的ActionBar,实现方式见上面NavigationView一节。
接下来就是将Toolbar放入到布局文件:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:background="?attr/colorPrimary"
android:layout_height="?android:attr/actionBarSize"/>
最后可以将Toobar作为“ActionBar”来用,对Toolbar设置Nav Icon、Logo、Title 、Sub Title、Menu Items。
关于字体的样式,可以在布局文件设置属性app:titleTextAppearance、app:subtitleTextAppearance或者代码setTitleTextAppearance、setSubTitleTextAppearance设置。
至于Menu Item,依然支持在menu/menu_main.xml中去声明,然后复写onCreateOptionsMenu和onOptionsItemSelected即可。
也可以通过toolbar.setOnMenuItemClickListener实现点击MenuItem的回调。
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if(item.getItemId() == ...) {
/**do something*/
return true;
}
return false;
}
});
Java代码实现:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("这里是Title");
toolbar.setSubtitle("这里是子标题");
toolbar.setLogo(R.drawable.head);
toolbar.setNavigationIcon(R.drawable.ic_menu);
setSupportActionBar(toolbar);
@Override
public boolean onOptionsItemSelected(MenuItem item) {
/**监听Nav Icon的点击事件*/
if(item.getItemId() == android.R.id.home) {
Toast.makeText(MainActivity.this,"NavigationIcon clicked",Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
AppBarLayout 是继承LinerLayout实现的一个ViewGroup容器组件,它是为了Material Design设计的App Bar,支持手势滑动操作。默认的AppBarLayout是垂直方向的,它的作用是把AppBarLayout包裹的内容都作为AppBar。
下面演示将Toolbar 和TabLayout的组合部分共同构成 AppBar的效果。
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="?attr/colorPrimary" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="?attr/colorPrimary"
app:tabIndicatorColor="#ffffff00"
app:tabIndicatorHeight="5dp"
app:tabMode="fixed"
app:tabSelectedTextColor="#ffff0000"
app:tabTextColor="#ffffffff" />
</android.support.design.widget.AppBarLayout>
注: AppBarLayout必须作为Toolbar的父布局容器
AppBarLayout是支持手势滑动效果的,不过要和CoordinatorLayout配合使用,接下来学习一下CoordinatorLayout组件怎么使用。
CoordinatorLayout是这次新添加的一个增强型的FrameLayout。在CoordinatorLayout中,我们可以在FrameLayout的基础上完成很多新的操作。它的作用主要是协调子view之间触摸事件的布局。
首先看一个例子,当你将FloatingActionButton作为一个子View添加进CoordinatorLayout并且将CoordinatorLayout传递给 Snackbar.make(),在3.0及其以上的设备上,Snackbar不会显示在悬浮按钮的上面,而是FloatingActionButton利用CoordinatorLayout提供的回调方法,在Snackbar以动画效果进入的时候自动向上移动让出位置,并且在Snackbar动画地消失的时候回到原来的位置,不需要额外的代码。
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/good"
android:layout_gravity="center_horizontal"
app:backgroundTint="#ff0000ff"
app:elevation="6dp"
app:fabSize="mini"
app:pressedTranslationZ="12dp"
app:rippleColor="#ff00ff00" />
</android.support.design.widget.CoordinatorLayout>
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorLayout);
...
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.snackBar:
Snackbar.make(coordinatorLayout, "Snackbar comes out", Snackbar.LENGTH_LONG)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText( MainActivity.this,"Toast comes out",Toast.LENGTH_SHORT).show();
}
}).show();
break;
default:
break;
}
}
再来看看官方给出的例子:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"/>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="?attr/colorPrimary"
app:tabIndicatorColor="#ffffff00"
app:tabIndicatorHeight="5dp"
app:tabMode="fixed"
app:tabSelectedTextColor="#ffff0000"
app:tabTextColor="#ffffffff"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
从上面布局看到,CoordinatorLayout协调布局中包裹了两个布局,一个是RecyclerView,一个是AppBarLayout,并且:
1、给这个可滚动组件设置了layout_behavior
2、给另一个控件设置了layout_scrollFlags
为滚动的布局设置layout_behavior属性后,这个布局会自动移动到AppBarLayout以下(类似MarginTop)。而且,当设置了layout_behavior的控件滑动时,就会触发设置了layout_scrollFlags的控件发生状态的改变。
layout_behavior:coordinatorlayout可以协调子view之间的触动事件,每一个子view需要有各自的滑动处理方式。该属性就是用来指定处理自己滑动事件的Behavior对象。因此,该属性的值为自定义Behavior子类的全名(即包名+类名)。本例如下:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
...
<string name="appbar_scrolling_view_behavior" translatable="false">android.support.design.widget.AppBarLayout$ScrollingViewBehavior</string>
layout_scrollFlags有如下几种选项:
需要注意的是,后面两种模式基本只有在CollapsingToolbarLayout才有用,而前面两种模式基本是需要一起使用的,也就是说,这些flag的使用场景,基本已经固定了。
例如我们前面例子中的,也就是这种模式:
app:layout_scrollFlags="scroll|enterAlways"
我们上面的布局中 给Toolbar设置了app:layout_scrollFlags属性,因此,Toolbar是可以滚动出屏幕,且向下滚动又可以出现。
为了使得Toolbar可以滑动,我们必须还得有个条件,就是CoordinatorLayout布局下包裹一个具有滑动效果的组件,比如 RecyclerView,NestedScrollView(经过测试,ListView,ScrollView不支持)。并且给这些组件设置layout_behavior属性来告诉CoordinatorLayout,该组件是带有滑动行为的组件,然后CoordinatorLayout在接受到滑动时会通知AppBarLayout 中可滑动的Toolbar可以滑出屏幕了。
注:所有使用scrollFlags的view都必须定义在没有使用scrollFlags的view的前面,这样才能确保所有的view从顶部退出,留下固定的元素。
CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承自FrameLayout,给它设置layout_scrollFlags,它可以控制包含在CollapsingToolbarLayout中的控件(如:ImageView、Toolbar)在响应layout_behavior事件时作出相应的scrollFlags滚动事件(移除屏幕或固定在屏幕顶端)。
使用CollapsingToolbarLayout:
<android.support.design.widget.CoordinatorLayout 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="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="#30469b"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/ic_banner"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7" />
<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.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
我们在CollapsingToolbarLayout中设置了一个ImageView和一个Toolbar。并把这个CollapsingToolbarLayout放到AppBarLayout中作为一个整体。
(1)在CollapsingToolbarLayout中,设置了app:layout_scrollFlags=”scroll|exitUntilCollapsed”。关于layout_scrollFlags的值意义见上面。
其中还设置了一些属性,简要说明一下:
contentScrim – 设置当完全CollapsingToolbarLayout折叠(收缩)后的背景颜色。
expandedTitleMarginStart – 设置扩张时候(还没有收缩时)title向左填充的距离。
(2)在ImageView控件中,我们设置了:
layout_collapseMode (折叠模式) – 有两个值:
layout_collapseParallaxMultiplier(视差因子) - 设置视差滚动因子,值为:0~1。
(3)在Toolbar控件中,我们设置了layout_collapseMode(折叠模式):为pin。
综上分析:当设置了layout_behavior的控件响应起了CollapsingToolbarLayout中的layout_scrollFlags事件时,ImageView会有视差效果的向上滚动移除屏幕,当开始折叠时CollapsingToolbarLayout的背景色(也就是Toolbar的背景色)就会变为我们设置好的背景色,Toolbar也一直会固定在最顶端。
效果如图:
Java代码:
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
/**使用CollapsingToolbarLayout必须把title设置到CollapsingToolbarLayout上,设置到Toolbar上则不会显示*/
mCollapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar_layout);
mCollapsingToolbarLayout.setTitle("CollapsingToolbarLayout");
//通过CollapsingToolbarLayout修改字体颜色
mCollapsingToolbarLayout.setExpandedTitleColor(Color.WHITE);//设置还没收缩时状态下字体颜色
mCollapsingToolbarLayout.setCollapsedTitleTextColor(Color.GREEN);//设置收缩后Toolbar上字体的颜色
注:使用CollapsingToolbarLayout时必须把title设置到CollapsingToolbarLayout上,设置到Toolbar上不会显示。
Demo下载地址