篇章目标要点
此前看到一些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
<application
android: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.CoordinatorLayout
xmlns: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.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="vertical">
<com.google.android.material.appbar.CollapsingToolbarLayout
android: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表示折叠过程中位置始终不会变-->
<ImageView
android: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.Toolbar
android: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.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!--RecyclerView为内容-->
<androidx.recyclerview.widget.RecyclerView
android: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]";
@Override
protected 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的显示属于常规知识,这里没有放置相关代码。如果需要,可以提问提供邮箱,我这边可以单独提供相应的代码片段。
|