使用CoordinatorLayout打造各种炫酷的效果
自定义behavior —— 仿知乎,floatactionbutton隐藏与展示
viewpager,scrollview 嵌套viewpager滑动冲突解决
自定义 behavior - 完美仿 qq 浏览器首页,美团商家详情页
coordinatorlayout简介
coordinatorlayout是在 google io/15 大会发布的,遵循material 风格,包含在 support library中,结合appbarlayout, collapsingtoolbarlayout等 可 产生各种炫酷的效果
coordinatorlayout简介通常用来 干什么
coordinatorlayout is intended for two primary use cases:
as a top-level application decor or chrome layout
as a container for a specific interaction with one or more child views
简单来说就是
- 作为最上层的view
- 作为一个 容器与一个或者多个子view进行交互
下面我们一起先来看一下我们实现的效果图
动态图
结合toolbar
结合viewpager
结合viewpager的视觉特差
appbarlayout
它是继承与linearlayout的,默认 的 方向 是vertical
类型 | 说明 |
---|---|
int scroll_flag_enter_always | when entering (scrolling on screen) the view will scroll on any downwards scroll event, regardless of whether the scrolling view is also scrolling. |
int scroll_flag_enter_always_collapsed | an additional flag for 'enteralways' which modifies the returning view to only initially scroll back to it's collapsed height. |
int scroll_flag_exit_until_collapsed | when exiting (scrolling off screen) the view will be scrolled until it is 'collapsed'. |
int scroll_flag_scroll | the view will be scroll in direct relation to scroll events. |
int scroll_flag_snap | upon a scroll ending, if the view is only partially visible then it will be snapped and scrolled to it's closest edge. |
类型 | 说明 |
---|---|
int scroll_flag_enter_always | w((entering) / (scrolling on screen))下拉的时候,这个view也会跟着滑出。 |
int scroll_flag_enter_always_collapsed | 另一种enteralways,但是只显示折叠后的高度。 |
int scroll_flag_exit_until_collapsed | ((exiting) / (scrolling off screen))上拉的时候,这个view会跟着滑动直到折叠。 |
int scroll_flag_scroll | 这个view将会响应scroll事件 |
int scroll_flag_snap | 在scroll滑动事件结束以前 ,如果这个view部分可见,那么这个view会停在最接近当前view的位置 |
我们可以通过两种 方法设置这个flag
- 方法一
setscrollflags(int)
- 方法二
app:layout_scrollflags="scroll|enteralways"
注意事项
appbarlayout必须作为coordinatorlayout的直接子view,否则它的大部分功能将不会生效,如layout_scrollflags等。
首先我们先来看一下我们 效果图一是怎样实现的
代码
<android.support.design.widget.coordinatorlayout android:id="@+id/main_content" 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: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="?attr/actionbarsize" android:background="?attr/colorprimary" app:layout_scrollflags="scroll|enteralways" app:popuptheme="@style/themeoverlay.appcompat.light"/> . </android.support.design.widget.appbarlayout> <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.floatingactionbutton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_margin="15dp" android:src="@drawable/add_2"/> </android.support.design.widget.coordinatorlayout>
思路 分析
从图中我们可以知道 layout_scrollflags="scroll|enteralways,
前面已经说到layout_scrollflags=scroll的时候,这个view会 跟着 滚动 事件响应,
layout_scrollflags=“enteralways”的时候 这个view会响应下拉事件
所以呈现出来的结果应该是我们在上拉的时候toolbar 会隐藏,下拉的时候toolbar会出来
那如果当我们的toolbar 等于 app:layout_scrollflags="scroll|snap"的时候 ,
layout_scrollflags=scroll的时候,这个view会 跟着 滚动 事件响应,
layout_scrollflags=“snap”的时候 在scroll滑动事件结束以前 ,如果这个view部分可见,那么这个view会停在最接近当前view的位置。
综上呈现的效果如下,代码见toolbarsamplesnar的布局文件
结合viewpager
布局代码如下
<android.support.design.widget.coordinatorlayout android:id="@+id/main_content" 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="250dp"> <imageview android:layout_width="match_parent" android:layout_height="200dp" android:background="?attr/colorprimary" android:scaletype="fitxy" android:src="@drawable/tangyan" app:layout_scrollflags="scroll|enteralways"/> <android.support.design.widget.tablayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignparentbottom="true" android:background="?attr/colorprimary" app:tabindicatorcolor="@color/coloraccent" app:tabindicatorheight="4dp" app:tabselectedtextcolor="#000" app:tabtextcolor="#fff"/> </android.support.design.widget.appbarlayout> <android.support.v4.view.viewpager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> <android.support.design.widget.floatingactionbutton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_margin="15dp" android:src="@drawable/add_2"/> </android.support.design.widget.coordinatorlayout>
思路分析
其实相对于前 一个例子,只是把 摆放recyclerview 的位置替换成viewpager而已,为了有页面导航器的效果,再使用 tablayout而已,而tablayout 在我们滑动的时候最终会停靠在 最顶部,是因为我们没有设置其layout_scrollflags,即tablayout是静态的
运行以后,即可看到以下的结果
下面我们一起来看一下 tablayout是怎样结合viewpager直线 导航器的效果的
代码注释 里面已经解释地很清楚了 ,这里我就不解释了
public class viewpagersample extends appcompatactivity { viewpager mviewpager; list<fragment> mfragments; string[] mtitles = new string[]{ "主页", "微博", "相册" }; private tablayout mtablayout; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_third); // 第一步,初始化viewpager和tablayout mviewpager = (viewpager) findviewbyid(r.id.viewpager); mtablayout = (tablayout) findviewbyid(r.id.tabs); setupviewpager(); } private void setupviewpager() { mfragments = new arraylist<>(); for (int i = 0; i < mtitles.length; i++) { listfragment listfragment = listfragment.newinstance(mtitles[i]); mfragments.add(listfragment); } // 第二步:为viewpager设置适配器 basefragmentadapter adapter = new basefragmentadapter(getsupportfragmentmanager(), mfragments, mtitles); mviewpager.setadapter(adapter); // 第三步:将viewpager与tablelayout 绑定在一起 mtablayout.setupwithviewpager(mviewpager); } }
如果我们想更改indicator的相关样式,我们可以在布局文件里面使用
<android.support.design.widget.tablayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignparentbottom="true" android:background="?attr/colorprimary" app:tabindicatorcolor="@color/coloraccent" app:tabindicatorheight="4dp" app:tabselectedtextcolor="#000" app:tabtextcolor="#fff"/>
如果你不想使用google 帮我们 封装好的控件的话,你也可以自己自定义一个控件,你可以参考我的这一篇博客
在看例子结合viewpager的视觉特差之前 ,我们需要先了解collapsingtoolbarlayout这个控件
collapsingtoolbarlayout
collapsingtoolbarlayout继承与framelayout,官网地址,请自备*。
简单来说 ,collapsingtoolbarlayout是工具栏的包装器,它通常作为appbarlayout的孩子。主要实现以下功能
- collapsing title(可以折叠 的 标题 )
- content scrim(内容装饰),当我们滑动的位置 到达一定阀值的时候,内容 装饰将会被显示或者隐藏
- status bar scrim(状态栏布)
- parallax scrolling children,滑动的时候孩子呈现视觉特差效果
- pinned position children,固定位置的 孩子
下面我们一起来看一下几个常量
常量 | 解释说明 |
---|---|
int collapse_mode_off | the view will act as normal with no collapsing behavior.(这个 view将会 呈现正常的结果,不会表现出折叠效果) |
int collapse_mode_parallax | the view will scroll in a parallax fashion. see setparallaxmultiplier(float) to change the multiplier used.(在滑动的时候这个view 会呈现 出 视觉特差效果 ) |
int collapse_mode_pin | the view will pin in place until it reaches the bottom of the collapsingtoolbarlayout.(当这个view到达 collapsingtoolbarlayout的底部的时候,这个view 将会被放置,即代替整个collapsingtoolbarlayout) |
我们有两种方法可以设置这个常量,
方法一:在代码中使用这个方法
setcollapsemode(int collapsemode)
方法 二:在布局文件中使用自定义属性
app:layout_collapsemode="pin"
到此 ,collapsingtoolbarlayout的一些重要属性已经讲解完毕,下面我们一起来看一下我们是怎样结合viewpager实现视差效果的
结合viewpager的视觉特差
布局代码
<?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" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/background_light" android:fitssystemwindows="true" > <android.support.design.widget.appbarlayout android:id="@+id/main.appbar" android:layout_width="match_parent" android:layout_height="300dp" android:fitssystemwindows="true" android:theme="@style/themeoverlay.appcompat.dark.actionbar" > <android.support.design.widget.collapsingtoolbarlayout android:id="@+id/main.collapsing" android:layout_width="match_parent" android:layout_height="250dp" android:fitssystemwindows="true" app:contentscrim="?attr/colorprimary" app:expandedtitlemarginend="64dp" app:expandedtitlemarginstart="48dp" app:layout_scrollflags="scroll|exituntilcollapsed" > <imageview android:id="@+id/main.backdrop" android:layout_width="match_parent" android:layout_height="match_parent" android:fitssystemwindows="true" android:scaletype="centercrop" android:src="@drawable/tangyan" 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" app:popuptheme="@style/themeoverlay.appcompat.light" /> </android.support.design.widget.collapsingtoolbarlayout> <android.support.design.widget.tablayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignparentbottom="true" android:background="?attr/colorprimary" app:tabindicatorcolor="@color/coloraccent" app:tabindicatorheight="4dp" app:tabselectedtextcolor="#000" app:tabtextcolor="#fff"/> </android.support.design.widget.appbarlayout> <android.support.v4.view.viewpager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> </android.support.v4.view.viewpager> <android.support.design.widget.floatingactionbutton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_margin="15dp" android:src="@drawable/add_2"/> </android.support.design.widget.coordinatorlayout>
效果图如下
思路解析
-
结构图如图片所示,先说明collapsingtoolbarlayout的变化
collapsingtoolbarlayout里面 包含imageview 和toolbar,imageview的app:layout_collapsemode="parallax",表示视差效果,toolbar的 app:layout_collapsemode="pin",当这个toobar到达 collapsingtoolbarlayout的底部的时候,会代替整个collapsingtoolbarlayout显示
-
接着说明tablayout的变化
从前面的描述我们已经知道当 没有指定app:layout_scrollflags的时候,最终tablayout会静止,不会随着滑动的 时候消失不见
拓展
如果我们仅仅 改变collapsingtoolbarlayout的app:layout_scrollflags="scroll|exituntilcollapsed|snap"的时候,其它代码不变,运行以后,我们将可以看到如下效果图
总结
这篇博客主要讲解了coordinatorlayout,appbarlayout,collapsingtoolbarlayout的一些相关属性。
- 对于appbarlayout,我们主要 讲解了这个属性app:layout_scrollflags,设置不同 的属性我们可以在滚动的时候显示不同 的效果
- 对于collapsingtoolbarlayout,我们主要讲解了app:layout_collapsemode这个属性,设置不同的值,我们可以让其子view呈现不同的 炫酷效果,如parallax和pin等
coordinatorlayout的相关用法还有很多,有兴趣 了解的请自行阅读: 官方文档地址
题外话
coordinatorlayout这个控件真的很强大,使用它可以实现各种炫酷的效果,简化了开发者的许多工作,有能力的话可以去研究一下源码 ,看是怎样实现的?
参考文章:android-[译]掌握coordinatorlayout
源码下载地址:https://github.com/gdutxiaoxu/coordinatorlayoutexample.git
欢迎大家关注我的微信公众号号 stormjun949(徐公码字),即可关注。 目前专注于 android 开发,主要分享 android开发相关知识和一些相关的优秀文章,包括个人总结,职场经验等。
上一篇: ECharts grid组件离容器的距离
下一篇: 某业务自助开通账户问题排查