篇章目标要点
此前看到一些app有着炫酷的可折叠的UI,心里想着如果哪一天我也可以自己动手实现这些美观的UI就好了。偶然中发现了安卓提供的Material Design的妙用,决定动手实现向往已久的可折叠标题栏。本文的主要是讲述Material Design组件中的CollapsingToolbarLayout实现可折叠标题栏的过程,中间会穿插着AppBarLayout控件的用法
实现效果
首先放置一下完成的效果,如以下视频所示,打开页面时可以看到完整的标题栏,此时标题栏专辑封面是铺开状态,随着向上的滑动动作,专辑封面逐步被折叠收起,随后在滑动过程中RecyclerView的顶部标题栏也实现了置顶的效果。
折叠过程剖析
折叠标题栏主要由AppBarLayout, CollapsingToolbarLayout可折叠布局, Layout吸顶布局三部分构成。
(1)AppBarLayout:作为折叠布局的外部容器,是整个页面的标题栏,CollapsingToolbarLayout可折叠布局, Layout吸顶布局是其子视图。
(2)CollapsingToolbarLayout可折叠布局, 内部设置专辑图大封面以及ToolBar,在折叠状态时ToolBar可充当ActionBar功能。
(3)Layout吸顶布局:为了配合RecyclerView显示而设计,一般用来标示RecyclerView各元素的含义。其放置在AppBarLayout中的作用是实现置顶效果
展开状态的布局:
折叠状态的布局:
在展开状态时,在向上滑动的过程,首先会执行CollapsingToolbarLayout折叠过程,折叠完成后,相应的滑动事件会给到RecyclerView消耗;在折叠状态时,向下滑动会先将RecyclerView内容滑动至顶部,然后才会展开CollapsingToolbarLayout布局
添加依赖
该任务实现过程主要用到了Material Design库和Glide库,其依赖如下
implementation 'com.google.android.material:material:1.0.0'implementation 'com.github.bumptech.glide:glide:4.6.1'
代码实现过程
(1)在values/styles文件中为折叠标题栏自定义Theme,需要继承Theme.AppCompat,并且设置屏蔽原来自带的ActionBar,设置无标题
<!--为了实现自定义ActionBar,需要屏蔽原来自带的ActionBar,并且设置无标题--><style name="NoActionBar" parent="Theme.AppCompat"><item name="windowActionBar">false</item><item name="windowNoTitle">true</item></style>
然后在AndroidManifest中Application或者Activity的属性中引用该style
<applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/NoActionBar">...
(2)Layout定义,由于为了追求实现效率,我是放在MainActivity中直接实现的。你可以根据实际需要决定在Fragment或者MainActivity创建布局,以下提供的是一种思路
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayoutxmlns: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=".MainActivity"><!--定义标题栏内容--><com.google.android.material.appbar.AppBarLayoutandroid:id="@+id/app_bar"android:layout_width="match_parent"android:layout_height="250dp"android:orientation="vertical"><com.google.android.material.appbar.CollapsingToolbarLayoutandroid:id="@+id/collapsing_toolbar_layout"android:layout_width="match_parent"android:layout_height="200dp"android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"app:contentScrim="?attr/colorPrimary"app:layout_scrollFlags="scroll|exitUntilCollapsed"><!--定义标题栏内容, image view设置成parallax折叠过程可以产生一定的错位位移,toolbar设置成pin表示折叠过程中位置始终不会变--><ImageViewandroid:id="@+id/image_view_title"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop"app:layout_collapseMode="parallax"/><!--toolbar设置成pin表示折叠过程中位置始终不会变--><androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"app:layout_collapseMode="pin"/></com.google.android.material.appbar.CollapsingToolbarLayout><!--为了配合RecyclerView显示,设置了此置顶布局,作用是提示RecyclerView各元素的含义--><include layout="@layout/linear_layout_recycler_view_title"android:layout_width="match_parent"android:layout_height="50dp"android:layout_gravity="bottom"app:layout_collapseMode="pin" /></com.google.android.material.appbar.AppBarLayout><!--定义可滑动内容栏--><androidx.core.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="@string/appbar_scrolling_view_behavior"><!--RecyclerView为内容--><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"/></androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
当中引用的置顶布局是外部引用,由于较为简单,不展示相应代码了。
(3)代码实现
代码实现过程较为简单,主要包括设置CollapsingToolbarLayout 折叠布局的标题,通过Glide加载其内部的专辑封面图片内容;设置ActionBar ; 最后就是设置RecyclerView显示。代码过程是比较简单的,以下代码中已有较多注释,在此不做赘述了。
public class MainActivity extends AppCompatActivity {/*** 可折叠标题栏的图片和标题*/private final static String TITLE_NAME = "杨幂";private final static String TITLE_IMAGE = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwx4.sinaimg.cn%2Fmw690%2F001SZrlUly1gum6uspyb4j616s0u0ad002.jpg&refer=http%3A%2F%2Fwx4.sinaimg.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1634697003&t=4b2e89e9c1019b127c25d8d2f91e6a04";private final static String TITLE_CONTENT = "2005年,杨幂进入北京电影学院表演系本科班就读。2006年,因出演金庸武侠剧《神雕侠侣》而崭露头角。2008年,凭借古装剧《王昭君》获得第24届中国电视金鹰奖观众喜爱的电视剧女演员奖提名 [1] 。2009年,杨幂在“80后新生代娱乐大明星”评选活动中与其她三位女演员共同被评为“四小花旦” [2] 。2011年,因主演穿越剧《宫锁心玉》赢得广泛关注 [3] ,并获得第17届上海电视节白玉兰奖观众票选最具人气女演员奖 [4] 。\n" +"2012年,杨幂工作室成立,而她则凭借都市剧《北京爱情故事》相继获得第9届中国金鹰电视艺术节最具人气女演员奖 [5] 、第26届中国电视金鹰奖观众喜爱的电视剧女演员奖提名 [6] 。2015年,主演的《小时代》系列电影票房达到了18亿人民币 [7] 。2016年,其主演的职场剧《亲爱的翻译官》取得全国年度电视剧收视冠军 [8] 。2017年,杨幂主演的神话剧《三生三世十里桃花》获得颇高关注;同年,她还凭借科幻片《逆时营救》获得休斯顿国际电影节最佳女主角奖 [9] 。2018年,凭借古装片《绣春刀Ⅱ:修罗战场》获得北京大学生电影节最受大学生欢迎女演员奖 [10] ;同年,她还获得了第五届中国电视好演员奖绿宝石女演员奖 [11] 。2021年,首次参加中央广播电视总台春节联欢晚会 [12]";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout);ImageView imageViewTitle = findViewById(R.id.image_view_title);//设置折叠布局内部的toolbar在折叠时可充当ActionBar标题栏Toolbar toolbar = findViewById(R.id.toolbar);setSupportActionBar(toolbar);ActionBar actionBar = getSupportActionBar();if(null != actionBar){actionBar.setDisplayHomeAsUpEnabled(true);}//设置折叠标题栏的标题collapsingToolbarLayout.setTitle(TITLE_NAME);//设置折叠标题栏的封面图片RequestOptions options = RequestOptions.placeholderOf(R.drawable.picture_example);Glide.with(this).load(TITLE_IMAGE).apply(options).into(imageViewTitle);RecyclerView recyclerView = findViewById(R.id.recycler_view);LinearLayoutManager layoutManager = new LinearLayoutManager(this);recyclerView.setLayoutManager(layoutManager);//设置RecyclerView内容SongAdapter adapter = new SongAdapter(getTrackList(30));recyclerView.setAdapter(adapter);//设置RecyclerView的分割线DividerItemDecoration itemDecoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);itemDecoration.setDrawable(getResources().getDrawable(R.drawable.inset_divider, null));recyclerView.addItemDecoration(itemDecoration);}/*** 构建RecyclerView显示数据*/private final static String[] singers = {"杨幂","王力宏","周杰伦"};private final static String[] tracks = {"爱的供养","天知道","简单爱"};private final static String[] pictures = {"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fedpic%2Fe6%2F68%2F5c%2Fe6685c22535ec3b00a4986ea340e94d6.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1634711345&t=9d6b4ed0fcc4b9e6061e16852da09b81","https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fqna.smzdm.com%2F202105%2F09%2F6097ee6181d4d1458.jpg_a200.jpg&refer=http%3A%2F%2Fqna.smzdm.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1634711454&t=fd670dd2562e2bc36ecb61242ba62b46","https://gss0.baidu.com/70cFfyinKgQFm2e88IuM_a/baike/pic/item/7ac880515fcd8e6c43a75b63.jpg"};private List<TrackBean> getTrackList(int size){List<TrackBean> trackBeans = new ArrayList<>();int index = 0;for(int i = 0; i < size; i++){TrackBean bean = new TrackBean();index = i%singers.length;bean.setSingerName(singers[index]);bean.setTrackName(tracks[index]);bean.setSingerPicture(pictures[index]);trackBeans.add(bean);index++;}return trackBeans;}
}
学习心得
在安卓提供的Material Design框架的支持下,如此绚丽的可折叠标题栏很简单就实现了。但是个人认为当中的核心思想是CollapsingToolbarLayout 在滑动时间分发的管理上是值得我们学习的,这个后续要进一步通过学习其源码掌握相关知识点。RecyclerView的显示属于常规知识,这里没有放置相关代码。如果需要,可以提问提供邮箱,我这边可以单独提供相应的代码片段。