我很是喜欢Material Design里折叠工具栏的效果,bilibili Android客户端视频详情页就是采用的这种设计。这篇文章的第二部分咱们就经过简单的模仿bilibili视频详情页的实现来了解下CollapsingToolbarLayout的使用。文章的第三部分介绍了CollapsingToolbarLayout与TabLayout的组合使用。php
有基础的朋友能够直接跳过第一部分。java
Android studio中有一个Activity模板叫ScrollingActivity,它实现的就是简单的可折叠工具栏,咱们将此模板添加到项目中。android
ScrollingActivity的布局代码以下git
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <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/AppTheme.PopupOverlay" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/text_margin" android:text="@string/large_text" /> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/fab_margin" android:src="@android:drawable/ic_dialog_email" app:layout_anchor="@id/app_bar" app:layout_anchorGravity="bottom|end" /> </android.support.design.widget.CoordinatorLayout>
AppBarLayout是一种支持响应滚动手势的app bar布局(好比工具栏滚出或滚入屏幕),CollapsingToolbarLayout则是专门用来实现子布局内不一样元素响应滚动细节的布局。github
与AppBarLayout组合的滚动布局(Recyclerview、NestedScrollView等)须要设置app:layout_behavior="@string/appbar_scrolling_view_behavior"(上面代码中NestedScrollView控件所设置的)。没有设置的话,AppBarLayout将不会响应滚动布局的滚动事件。app
CollapsingToolbarLayout和ScrollView一块儿使用会有滑动bug,注意要使用NestedScrollView来替代ScrollView。ide
AppBarLayout的子布局有5种滚动标识(就是上面代码CollapsingToolbarLayout中配置的app:layout_scrollFlags属性):工具
CollapsingToolbarLayout能够经过app:contentScrim设置折叠时工具栏布局的颜色,经过app:statusBarScrim设置折叠时状态栏的颜色。默认contentScrim是colorPrimary的色值,statusBarScrim是colorPrimaryDark的色值。这个后面会用到。布局
CollapsingToolbarLayout的子布局有3种折叠模式(Toolbar中设置的app:layout_collapseMode)学习
当CollapsingToolbarLayout的子布局设置了parallax模式时,咱们还能够经过app:layout_collapseParallaxMultiplier设置视差滚动因子,值为:0~1。
FloatingActionButton这个控件经过app:layout_anchor这个设置锚定在了AppBarLayout下方。FloatingActionButton源码中有一个Behavior方法,当AppBarLayout收缩时,FloatingActionButton就会跟着作出相应变化。关于CoordinatorLayout和Behavior,我下一篇文章会和你们一块儿学习。
这一堆属性看着有点烦,你们能够新建一个ScrollingActivity模板去实验一下玩玩。
咱们先对原界面分析一下。
界面初始,CollapsingToolbarLayout是展开状态,显示的是视频封面。咱们向上滚动界面,CollapsingToolbarLayout收缩。当AppBarLayout彻底折叠的时候视频av号隐藏,显示出来一个小电视图标和“当即播放”,点击则使AppBarLayout彻底展开,CollapsingToolbarLayout子布局由ImageView切换为视频弹幕播放器。
额...弹幕播放器...
B站很早就开源了一个弹幕引擎,还起了个狂拽酷炫吊炸天的名字叫“烈焰弹幕使 ”(一看就是二次元程序猿们的做品→_→),源码在github上,项目名叫DanmakuFlameMaster。
来咱们先看修改完成的布局。
<?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:id="@+id/coordinatorLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="@dimen/app_bar_height" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" app:statusBarScrim="@android:color/transparent" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> <!--封面图片--> <ImageView android:id="@+id/imageview" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/diqiu" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" android:fitsSystemWindows="true"/> <!--视频及弹幕控件--> <FrameLayout android:id="@+id/video_danmu" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" android:fitsSystemWindows="true" android:visibility="gone"> <VideoView android:id="@+id/videoview" android:layout_width="match_parent" android:layout_height="match_parent" /> <!--哔哩哔哩开源的弹幕控件--> <master.flame.danmaku.ui.widget.DanmakuView android:id="@+id/danmaku" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> <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/AppTheme.PopupOverlay" > <!--自定义带图片的当即播放按钮--> <android.support.v7.widget.ButtonBarLayout android:id="@+id/playButton" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:visibility="gone"> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:src="@mipmap/ic_play_circle_filled_white_48dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:text="当即播放" android:layout_gravity="center_vertical" /> </android.support.v7.widget.ButtonBarLayout> </android.support.v7.widget.Toolbar> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_scrolling" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/fab_margin" android:src="@mipmap/ic_play_circle_filled_white_48dp" app:layout_anchor="@id/app_bar" app:layout_anchorGravity="bottom|end" /> </android.support.design.widget.CoordinatorLayout>
我把colorPrimary的色值修改为了B站的“少女粉”,播放的图标是从网上找的。
<color name="colorPrimary">#FA7199</color>
由于咱们要实现沉浸式状态栏,因此就须要先把整个activity设置成状态栏透明模式。而后在布局文件中,把CollapsingToolbarLayout里要实现沉浸式的控件设置上android:fitsSystemWindows="true",若是没有设置,则子布局会位于状态栏下方,未延伸至状态栏。
布局并不算复杂,接下来先实现无弹幕播放时的功能,。
咱们须要监听CollapsingToolbarLayout的折叠、展开状态。唉我去,官方并无提供现成的方法(⊙_⊙?)。
查看源码,能够看到CollapsingToolbarLayout是经过实现AppBarLayout的OnOffsetChangedListener接口,根据AppBarLayout的偏移来实现子布局和title的视差移动以及ContentScrim和StatusBarScrim的显示。那么咱们也能够经过调用AppBarLayout的addOnOffsetChangedListener方法监听AppBarLayout的位移,判断CollapsingToolbarLayout的状态。
先写一个枚举定义出CollapsingToolbarLayout展开、折叠、中间,这三种状态。
private CollapsingToolbarLayoutState state; private enum CollapsingToolbarLayoutState { EXPANDED, COLLAPSED, INTERNEDIATE }
接下来对AppBarLayout进行监听,判断CollapsingToolbarLayout的状态并实现相应的逻辑。
为了让你们对状态看着更直观,我在修改状态值的时候把title一块儿进行了修改。
使用CollapsingToolbarLayout的时候要注意,在完成CollapsingToolbarLayout设置以后再调用Toolbar的setTitle()等方法将没有效果,咱们须要改成调用CollapsingToolbarLayout的setTitle()等方法来对工具栏进行修改。(具体缘由各位亲去看下CollapsingToolbarLayout源码就知道了 ( ˙-˙ ) )
AppBarLayout app_bar=(AppBarLayout)findViewById(R.id.app_bar);
app_bar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { if (verticalOffset == 0) { if (state != CollapsingToolbarLayoutState.EXPANDED) { state = CollapsingToolbarLayoutState.EXPANDED;//修改状态标记为展开 collapsingToolbarLayout.setTitle("EXPANDED");//设置title为EXPANDED } } else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) { if (state != CollapsingToolbarLayoutState.COLLAPSED) { collapsingToolbarLayout.setTitle("");//设置title不显示 playButton.setVisibility(View.VISIBLE);//隐藏播放按钮 state = CollapsingToolbarLayoutState.COLLAPSED;//修改状态标记为折叠 } } else { if (state != CollapsingToolbarLayoutState.INTERNEDIATE) { if(state == CollapsingToolbarLayoutState.COLLAPSED){ playButton.setVisibility(View.GONE);//由折叠变为中间状态时隐藏播放按钮 } collapsingToolbarLayout.setTitle("INTERNEDIATE");//设置title为INTERNEDIATE state = CollapsingToolbarLayoutState.INTERNEDIATE;//修改状态标记为中间 } } } });
而后对播放按钮设置监听,点击则调用AppBarLayout的setExpanded(true)方法使工具栏展开。
哔哩哔哩客户端的title是固定不动的,能够调用CollapsingToolbarLayout的setTitleEnabled(false)方法实现。
视频播放时,调用 NestedScrollView的setNestedScrollingEnabled(false)方法可使AppBarLayout不响应滚动事件。
细心的朋友可能发现了哔哩哔哩客户端为了不视频封面图片颜色过浅影响状态栏信息的显示,加了一个渐变的不透明层。
实现渐变遮罩层很简单。先在res/drawable文件夹下新建了一个名为gradient的xml文件,其中代码以下:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#33000000" android:endColor="#00000000" android:angle="270" /> </shape>
shape节点中,能够经过android:shape来设置形状,默认是矩形。gradient节点中angle的值270是从上到下,0是从左到右,90是从下到上。起始颜色#33000000是20%不透明度的黑色,#00000000表示全透明。
而后在CollapsingToolbarLayout里的ImageView代码下面加上一个自定义view,背景设置为上面的渐变效果。
<View android:layout_width="match_parent" android:layout_height="40dp" android:background="@drawable/gradient" android:fitsSystemWindows="true" />
通常状态栏的高度大概在20dp左右,我为了让渐变效果比较天然,而且不过多影响图(mei)片(zi),把高度设置成了40dp。(状态栏能看清了,妹子脸也没黑,挺好 (๑• . •๑) )
我省略了弹幕播放的相关实现,接下来只要在播放按钮监听中写出封面图片的隐藏、视频和弹幕弹幕控件的显示初始化及播放逻辑,在AppBarLayout的三种状态监听中根据是否视频在播放写出其余相应逻辑就行了,感兴趣的朋友能够下载哔哩哔哩的“烈焰弹幕使”源码DanmakuFlameMaster玩玩。
B站点击追番或投硬币后会出现一个相似Snackbar的提示控件,能够经过我上一篇文章没时间解释了,快使用Snackbar!——Android Snackbar花式使用指南来实现,欢迎感兴趣的朋友去看看。
真的不是我懒得上代码了,真的…(基友:赶忙的,开黑了。 我:等等我,立刻来!\(≧▽≦)/)
CollapsingToolbarLayout与TabLayout组合使用的效果也不错。
来看下CollapsingToolbarLayout里的代码
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="250dp" android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:titleEnabled="false" android:fitsSystemWindows="true" app:contentScrim="@color/colorPrimary" app:statusBarScrim="@android:color/transparent" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> <ImageView android:id="@+id/imageview" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:adjustViewBounds="true" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" android:fitsSystemWindows="true" android:src="@drawable/girl2"/> <View android:layout_width="match_parent" android:layout_height="40dp" android:background="@drawable/gradient" android:fitsSystemWindows="true" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="96dp" android:minHeight="?attr/actionBarSize" android:gravity="top" app:layout_collapseMode="pin" app:title="hello" app:popupTheme="@style/AppTheme.PopupOverlay" app:titleMarginTop="15dp" /> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="45dp" android:layout_gravity="bottom" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpage" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior"> </android.support.v4.view.ViewPager> </android.support.design.widget.CoordinatorLayout>
TabLayout没有设置app:layout_collapseMode,在CollapsingToolbarLayout收缩时就不会消失。
CollapsingToolbarLayout收缩时的高度是Toolbar的高度,因此咱们须要把Toolbar的高度增长,给TabLayout留出位置,这样收缩后TabLayout就不会和Toolbar重叠。
Toolbar的高度增长,title会相应下移。android:gravity="top"方法使Toolbar的title位于Toolbar的上方,而后经过app:titleMarginTop调整下title距顶部高度,这样Toolbar就和原来显示的同样了。
CollapsingToolbarLayout还能够和Palette搭配使用,可是我感受在实际使用中有些坑,由于CollapsingToolbarLayout中的图片不肯定,Palette从图片中获取到的色彩极可能不是你想要的。
感兴趣的朋友能够本身查下Palette的用法。
就是这些。 []~( ̄▽ ̄)~*