最近利用业余时间,开发了一款基于懂球帝接口数据的足球资讯app,整体的UI也是仿照懂球帝设计的。这是一个比较综合的项目,用到了不少以前没用过的组件和api,而且产生了很多新的开发思路,有些实现方式也是自己琢磨的,所以值得做一些记录,可能还存在瑕疵和可以优化的地方,也希望大家给我多指正。
折叠式布局在app中已经十分常见,一方面它可以方便用户在同一个页面看到尽可能多的内容,另一方面它的动画效果也比较酷炫,给用户的体验十分良好。
实现折叠式布局主要需要用到的组件是CoordinatorLayout和AppBarLayoyt,通过这两个组件可以实现随着屏幕滑动将指定的组件A折叠,并将指定的组件B悬浮的效果;我们还可以结合CollapsingToolbarLayout和Toolbar实现随着屏幕滑动被CollapsingToolbarLayout包裹的部分被折叠成toolbar的效果。这样说可能还是有点抽象,我们可以先看一下实现的效果:
1、折叠组件:CoordinatorLayout+AppBarLayoyt
2、折叠toolbar:CoordinatorLayout+AppBarLayoyt+CollapsingToolbarLayout+Toolbar
看了实现效果是不是就一目了然了,图一实现了上滑时将搜索框折叠,并保持tablayout悬浮的效果;而图二实现了上滑时将球队基本信息(被CollapsingToolbarLayout包裹)折叠,同时保持tablayout悬浮。
这是整个页面 组件树的结构:
最外层的是CoordinatorLayout,翻译过来叫做协调者布局,根据google给出的定义:它主要作为页面的顶级布局或容器,用来管理、协调子view间的联动,子view通过指定具体的“行为”(Behavior类),CoordinatorLayout根据Behavior协调子view的联动。
在这里app_bar_layout和vp_main是main_layout的两个子view,我们需要给滑动视图 vp_main设置一个behavior以协调它在滑动时app_bar_layout可以监听到它的滑动。官方给我们提供了一个behavior方便滑动视图与AppBarLayout做相应的联动:@string/appbar_scrolling_view_behavior,它与AppBarLayout的ScrollingViewBehavior相对应,当设置了这个属性后,滑动组件vp_main就与AppBarLayout app_bar_layout相捆绑,捆绑完成之后,我们只需为app_bar_layout中需要折叠的子view设置相应的layout_scrollFlags,一旦vp_main开始滑动,就可以实现对应的折叠效果;
这里再看一下layout_scrollFlags是什么东东,它主要用于监听滑动视图的滑动,然后根据设置的值,做出响应,;总共可以设置五种标记:
1、scroll:子view(折叠视图)会随着滑动视图滑动而滑动,最终完全滑入或滑出屏幕(所谓折叠);其他标记都是在它的基础上增加了其他效果,因此在设置其他标记时,必须带上它;(scoll)
2、enterAlways:设置子view滑入屏幕时的效果;设置后,向下滑动时,子view先滑动进入屏幕,滑动视图再响应滑动;(scroll|enterAlways)
3、enterAlwaysCollapsed:在enterAlways的基础上,增加了一个最小高度的概念,需要给子view设置一个最小高度,当子view下滑到最小高度后,滑动视图开始滑动;当滑动视图滑动到最顶部后,子view再开始滑动,直到全部完全显示;(scroll|enterAlways|enterAlwaysCollapsed)
4、exitUntilCollapsed:设置子view滑出屏幕时的效果,这里也可以设置最小高度;向上滑动时,子view滑动到离开屏幕或到达最小高度(并停留在最小高度)后,滑动视图再滑动,;(scroll| exitUntilCollapsed)
5、snap:滑动时,当子view的25%滑入或滑出屏幕,整个子view都会滑入或滑出屏幕;(scroll| snap)
第一种效果符合scroll标记描述的场景,因此我们这里设置layout_scrollFlags为scroll;
我们再来梳理一下现在该结构下,整个页面滑动的流程:
用户滑动视图vp_main时,由于设置了layout_behavior:@string/appbar_scrolling_view_behavior,因此app_bar_layout可以监听到其滑动,它的子view search_layout响应 scroll 标记,先滑动自己,然后通知vp_main开始滑动,直到自己完全滑入或滑出屏幕,同时app_bar_layout中没有设置layout_scrollFlags的组件则不会受到滑动的影响,效果上就是app_bar_layout中的search_layout滑入或滑出了屏幕,而tab_main一直保持它在app_bar_layout中的位置。
最后附上xml:
首先还是来看看组件树的结构:
这里又引入了一个新的组件CollapsingToolbarLayout来实现对toolbar的折叠,它继承自FrameLayout,被设计成了AppBarLayout的直接子类,主要属性有:
contentScrim:设置完全折叠后toolbar的颜色
title:toolbar标题
titleEnabled:设置为true后,toolbar的title会随着滑动的偏移量缩放
layout_collapseMode:折叠模式,作用于子view,主要有两种:pin(钉子模式)和parallx(视差模式),设置了pin模式的子view在父view完全折叠后会被固定在顶端;而视差模式下的子view在滑动过程中会产生一种视差的动画效果(parallax fashion);
以上我们可以确定实现这种效果的思路:
将toolbar放在另一个子view layout_bg上(FrameLayout);由于这边不需要设置title的缩放效果,我们可以把titleEnabled设置为false;toolbar最终需要固定在顶端,并且需要改变颜色,因此我们将toolbar的折叠模式设置为pin,contentScrim设置为对应颜色,而layout_bg的折叠模式可以不设置,当然为了更友好的用户体验,可以设置为parallax;与第一种效果(折叠组件)同理,CollapsingToolbarLayout本身作为折叠视图在这个场景下,向上滑动时需要保持Toolbar的高度,因此设置成scroll|exitUntilCollapsed(这里我并没有设置minHeight,怀疑CollapsingToolbarLayout有默认的minHeight);同时还需要给滑动视图 vp_team设置layout_behavior:@string/appbar_scrolling_view_behavior;
附上xml:
在代码中动态设置toolbar title:
appBarLayout.addOnOffsetChangedListener((appBarLayout1, i) -> {
if(appBarLayout1.getTotalScrollRange()==Math.abs(i)){
toolBar.setTitle(team.getTeam_name());
}else {
toolBar.setTitle("");
}
});
本文主要介绍了通过CoordinatorLayout、AppBarLayout、CollapsingToolbarLayout实现折叠组件和折叠Toolbar的效果,看似只是几个组件的组合,但其中的知识点还是不少的,总结起来有如下几个要点需要注意:
1、CoordinatorLayout必须作为最外层的布局;
2、滑动视图需要添加behavior;
3、根据需要的折叠效果,选择合适的layout_scrollFlags;
4、CollapsingToolbarLayout必须作为AppBarLayout的直接子view;
5、Toolbar的layout_collapseMode需要设置为pin;