Android Design Support Library

来源:互联网 发布:英文写作润色软件 编辑:程序博客网 时间:2024/06/11 00:55

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的Theme

md的主题有:

  • @android:style/Theme.Material (dark version)
  • @android:style/Theme.Material.Light (light version)
  • @android:style/Theme.Material.Light.DarkActionBar

与之对应的Compat Theme:

  • Theme.AppCompat
  • Theme.AppCompat.Light
  • Theme.AppCompat.Light.DarkActionBar

我们可以根据我们的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

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

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>

Google API Doc 官方说明:
这里写图片描述

Floating Action Button

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

这里写图片描述

TabLayout

通过选项卡的方式切换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,当然你也可以通过以下方法或属性修改部分样式:

  • setItemBackgroundResource(int):给menu设置背景资源,对应的属性app:itemBackground
  • setItemIconTintList(ColorStateList):给menu的icon设置颜色,对应的属性app:itemIconTint
  • setItemTextColor(ColorStateList):给menu的item设置字体颜色,对应的属性app:itemTextColor

你可以通过设置一个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);

Toolbar

众所周知,在使用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

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

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有如下几种选项:

  • scroll: 所有想滚动出屏幕的view都需要设置这个flag, 没有设置这个flag的view将被固定在屏幕顶部。
  • enterAlways: 这个flag让任意向下的滚动都会导致该view变为可见,启用快速“返回模式”。
  • enterAlwaysCollapsed:当你的视图已经设置minHeight属性又使用此标志时,你的视图只能以最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。
  • exitUntilCollapsed: 向上滚动时收缩View,但可以固定Toolbar一直在上面。

需要注意的是,后面两种模式基本只有在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

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 (折叠模式) – 有两个值:

  • pin - 设置为这个模式时,当CollapsingToolbarLayout完全收缩后,Toolbar还可以保留在屏幕上。
  • parallax - 设置为这个模式时,在内容滚动时,CollapsingToolbarLayout中的View(比如ImageView)也可以同时滚动,实现视差滚动效果,通常和layout_collapseParallaxMultiplier(设置视差因子)搭配使用。

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下载地址

0 0