您现在的位置是:首页 > 文章详情

界面无小事(九): 做个好看的伸缩头部

日期:2018-08-23点击:333

github传送门


目录

  • 前言
  • 效果图
  • 快速上手
  • CollapsingToolbarLayout折叠模式
  • AppBarLayout滚动方式
  • CoordinatorLayout配合Snackbar
  • 自定义伸缩头部
  • 最后

前言

之前也是写了RecyclerView的内容, 这次再补充伸缩头部的实现. 港真, 伸缩头部是那种看到第一眼就会爱上的视图效果, 好看又简洁.

  • 本文内容较多, 需要10分钟以上阅读时间, 请合理安排, 收藏也是可以的哦~
  • 多图预警, 转载请说明出处, 感谢~

效果图

先上案例的效果图, 有兴趣再看下去:

case1
case2

快速上手

先来实操一下, 看看从默认的滚动模板(Scrolling Activity)到效果图要几步.

选择模板
  • 首先, 在Toolbar上面加入ImageView, 参数之后再说明.
<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" app:toolbarId="@+id/toolbar"> <ImageView android:id="@+id/iv_main" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:contentDescription="@string/desc" android:scaleType="centerCrop" app:layout_collapseMode="pin" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> 
  • 然后在java代码中使用Glide加载图片.

导包:

implementation 'com.github.bumptech.glide:glide:3.7.0' 
// 加载图片 ImageView ivMain = (ImageView) findViewById(R.id.iv_main); Glide.with(this).load(R.drawable.p5).into(ivMain); 
  • 看下效果:
阶段效果图

发现两个问题, 由于背景是白色, 标题栏字体颜色要变成黑色, 默认就是黑色, 所以就是删除xml中的主题设置. 当然, 如果你是深色背景, 这里就无需动它. 然后标题栏需要变成透明的.

将标题栏设置透明色

那由于5.0之前是不能变的, 将styles.xml从5.0区分开, 5.0之前什么都不做, 之后版本设置标题栏为透明色. 现在styles.xml中写入:

<style name="MyTheme" parent="AppTheme" /> 

然后复制styles.xml:

复制styles.xml

删除重复部分:

<resources> <style name="MyTheme" parent="AppTheme"> <item name="android:statusBarColor">@android:color/transparent</item> </style> </resources> 
  • 然后在配置文件设置新主题, 顺带改下标题名称, 再次运行看下效果:
// 设置标题 ActionBar supportActionBar = getSupportActionBar(); if (supportActionBar != null) { supportActionBar.setTitle(UIUtil.getString(R.string.p5)); } 
修正后效果图

这样就完成了.


CollapsingToolbarLayout折叠模式

app:layout_collapseMode="parallax" app:layout_collapseMode="pin" app:layout_collapseMode="none" 

从xml中的参数说吧, 来看CollapsingToolbarLayout的折叠模式. 下面我也是截了一段官方文档内容.

COLLAPSE_MODE_OFF int COLLAPSE_MODE_OFF The view will act as normal with no collapsing behavior. Constant Value: 0 (0x00000000) COLLAPSE_MODE_PARALLAX int COLLAPSE_MODE_PARALLAX The view will scroll in a parallax fashion. See setParallaxMultiplier(float) to change the multiplier used. Constant Value: 2 (0x00000002) COLLAPSE_MODE_PIN int COLLAPSE_MODE_PIN The view will pin in place until it reaches the bottom of the CollapsingToolbarLayout. Constant Value: 1 (0x00000001) 

列个表再看下:

参数 效果
none 视图将正常运行, 没有折叠行为
pin 视图将固定到位, 直到它到达CollapsingToolbarLayout的底部
parallax 视图将以视差方式滚动

是不是该怎么懵还是怎么懵, 来看效果图:

parallax模式
pin模式

注意看人物的脚, parallax模式下人物最终滑动到身体部位消失. pin模式下, 人物滑到脚部位消失. 也就是说, pin模式下, 下面的滚动视图和图片是同步滑动的, 但是这样的观感其实不好. parallax则改进了这一点, 看起来很和谐, 尽管两者不再同步, 这就是翻译后说的以视差方式滚动了.


AppBarLayout滚动方式

滚动方式主要依靠参数组合(scroll必须要), 列个表再看下效果图, 官方文档就不截了.

参数 效果
scroll 视图将滚动与滚动事件直接相关. 需要设置此标志才能使任何其他标志生效. 如果在此之前的任何兄弟视图没有此标志, 则此值无效.
exitUntilCollapsed 退出(滚动屏幕)时, 视图将滚动直到“折叠”. 折叠高度由视图的最小高度定义。
snap 在滚动结束时, 如果视图仅部分可见, 则它将被捕捉并滚动到其最近的边缘.
enterAlways 当进入(在屏幕上滚动)时, 无论滚动视图是否也在滚动, 视图都将滚动任何向下滚动事件. 这通常被称为“快速返回”模式.
enterAlwaysCollapsed 'enterAlways'的另一个标志, 它修改返回的视图, 最初只回滚到它的折叠高度. 一旦滚动视图到达其滚动范围的末尾, 该视图的其余部分将滚动到视图中. 折叠高度由视图的最小高度定义.
  • 看看单scroll的情况: app:layout_scrollFlags="scroll"
scroll

可以看到整个滚上去了, 没有保留Toolbar.

  • 那我现在用的是app:layout_scrollFlags="scroll|exitUntilCollapsed", 效果大家也见过了.
  • 喜闻乐见的吸附效果, app:layout_scrollFlags="scroll|snap", 例如, 还剩下25%没滚完, 松手就自己滚出去; 如果还有75%没滚完, 松手直接全部显示. 但是我感觉体验不好, 会让人有着操作不灵敏的错觉.
snap
  • 快速返回, 就是把滚出去的部分快速显示出来, 可以对比之前的返回速度来看: app:layout_scrollFlags="scroll|enterAlways"
enterAlways
  • 对比快速返回来看, 这个相对柔和一些, 可以理解为二段式的快速返回, 总之就是返回没有enterAlways那么迅速: app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
enterAlwaysCollapsed

CoordinatorLayout配合Snackbar

先来看看自带的点击悬浮按钮的效果:

默认效果

不让悬浮按钮吸附在Toolbar上, 将它放置到底部, 再看下效果:

android:layout_gravity="end|bottom" 
自动上移

如果不是CoordinatorLayout, 可就没有这种效果了哦.


自定义伸缩头部

再来看一个改动更大, 更自定义的. 先上效果图:

效果图

相比于之前的, 最大的变化在于对滚动幅度的监听. 依据滚动幅度变化Toolbar内容.

布局文件

先来看下主布局文件的变化, Toolbar包含了两个布局文件, 相互切换. 然后展开部分由之前的ImageView变成了一个布局文件, 这里要注意app:contentInsetLeft="0dp", app:contentInsetStart="0dp", 这个就像html的默认边距一样, 需要清零. 不写的话左侧有默认的边距.

<android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:layout_scrollFlags="scroll|exitUntilCollapsed" app:toolbarId="@+id/toolbar"> <include layout="@layout/open_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="?attr/actionBarSize" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:contentInsetLeft="0dp" app:contentInsetStart="0dp" app:layout_collapseMode="pin"> <include android:id="@+id/toolbar_open" layout="@layout/toolbar_open" /> <include android:id="@+id/toolbar_close" layout="@layout/toolbar_close" /> </android.support.v7.widget.Toolbar> </android.support.design.widget.CollapsingToolbarLayout> 

三个小的布局代码我就贴一个做栗子:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary"> <ImageView android:id="@+id/iv_first" android:layout_width="@dimen/twenty_four_dp" android:layout_height="@dimen/twenty_four_dp" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_centerVertical="true" android:layout_marginLeft="@dimen/twenty_dp" android:layout_marginStart="@dimen/twenty_dp" android:contentDescription="@string/desc" android:src="@android:drawable/btn_star_big_on" /> <ImageView android:id="@+id/iv_second" android:layout_width="@dimen/twenty_four_dp" android:contentDescription="@string/desc" android:layout_height="@dimen/twenty_four_dp" android:layout_centerVertical="true" android:layout_marginLeft="@dimen/twenty_dp" android:layout_marginStart="@dimen/twenty_dp" android:layout_toEndOf="@+id/iv_first" android:layout_toRightOf="@+id/iv_first" android:src="@android:drawable/btn_star_big_on" /> <ImageView android:id="@+id/iv_third" android:layout_width="@dimen/twenty_four_dp" android:layout_height="@dimen/twenty_four_dp" android:contentDescription="@string/desc" android:layout_centerVertical="true" android:layout_marginLeft="@dimen/twenty_dp" android:layout_marginStart="@dimen/twenty_dp" android:layout_toEndOf="@+id/iv_second" android:layout_toRightOf="@+id/iv_second" android:src="@android:drawable/btn_star_big_on" /> <ImageView android:id="@+id/iv_forth" android:layout_width="@dimen/twenty_four_dp" android:contentDescription="@string/desc" android:layout_height="@dimen/twenty_four_dp" android:layout_centerVertical="true" android:layout_marginLeft="@dimen/twenty_dp" android:layout_marginStart="@dimen/twenty_dp" android:layout_toEndOf="@+id/iv_third" android:layout_toRightOf="@+id/iv_third" android:src="@android:drawable/btn_star_big_on" /> <ImageView android:layout_width="@dimen/twenty_four_dp" android:layout_height="@dimen/twenty_four_dp" android:layout_centerVertical="true" android:layout_marginLeft="@dimen/twenty_dp" android:contentDescription="@string/desc" android:layout_marginStart="@dimen/twenty_dp" android:layout_toEndOf="@+id/iv_forth" android:layout_toRightOf="@+id/iv_forth" android:src="@android:drawable/btn_star_big_on" /> <View android:id="@+id/toolbar_close_mask" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> 

要点在最后的View, 这是一个遮罩, 依据滚动幅度变化其透明度起到遮罩效果.

AppBarLayout.OnOffsetChangedListener

官方文档写的很简单, 使用起来也不难. 添加implements AppBarLayout.OnOffsetChangedListener. 实现public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)方法.

@Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { int offset = Math.abs(verticalOffset); int scrollRange = appBarLayout.getTotalScrollRange(); if (offset <= scrollRange / 2) { mToolbarOpen.setVisibility(View.VISIBLE); mToolbarClose.setVisibility(View.GONE); float openPer = (float) offset / (scrollRange / 2); int openAlpha = (int) (255 * openPer); mToolbarOpenMask.setBackgroundColor(Color.argb(openAlpha, 48, 63, 159)); } else { mToolbarClose.setVisibility(View.VISIBLE); mToolbarOpen.setVisibility(View.GONE); float closePer = (float) (scrollRange - offset) / (scrollRange / 2); int closeAlpha = (int) (255 * closePer); mToolbarCloseMask.setBackgroundColor(Color.argb(closeAlpha, 48, 63, 159)); } float per = (float) offset / scrollRange; int alpha = (int) (255 * per); mContentMask.setBackgroundColor(Color.argb(alpha, 48, 63, 159)); } 

前面也说了, 就是变化遮罩透明度, 这个颜色是对应了布局中设置的颜色的, 否则过渡效果就不对了. 可以用下PS将colors.xml中6位颜色变成rgb填入.


最后

看到这里也很不容易啦(手动比心). 喜欢记得点赞, 有意见或者建议评论区见, 暗中关注我也是可以的哦~

顺带一提, 腾讯云+社区也将同步我的文章了, 目前还在审核中:
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=cji0h4jns3lw

github传送门


原文链接:https://yq.aliyun.com/articles/635065
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章