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

简介: github传送门目录前言效果图快速上手CollapsingToolbarLayout折叠模式AppBarLayout滚动方式CoordinatorLayout配合Snackbar自定义伸缩头部最后前言之前也是写了RecyclerView的内容, 这次再补充伸缩头部的实现.

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传送门


目录
相关文章
|
3月前
|
缓存 小程序 数据可视化
【社区每周】小程序授权弹层和菜单支持长辈版、无障碍版;AMPE情景智能新增widget卡片能力(2022年6月第一期)
【社区每周】小程序授权弹层和菜单支持长辈版、无障碍版;AMPE情景智能新增widget卡片能力(2022年6月第一期)
21 0
|
9月前
【项目经验】:项目中下拉框数据太多造成页面卡顿(二)
项目中下拉框数据太多造成页面卡顿(二)
|
Web App开发 iOS开发
必备技能11:网页一键变灰
必备技能11:网页一键变灰
必备技能11:网页一键变灰
如何实现一个丝滑的点击水波效果
本文为Varlet组件库源码主题阅读系列第九篇,读完本篇,可以了解到如何使用一个`div`创建一个点击的水波效果。
73 0
|
前端开发
前端工作总结278-弹性布局 修改样式
前端工作总结278-弹性布局 修改样式
73 0
前端工作总结278-弹性布局 修改样式
|
前端开发
前端工作总结129-首页样式调整第一次
前端工作总结129-首页样式调整第一次
69 0
前端工作总结129-首页样式调整第一次
|
前端开发
前端工作总结104-控制弹出框不全屏
前端工作总结104-控制弹出框不全屏
57 0
html+css实战179-快捷导航布局-内容
html+css实战179-快捷导航布局-内容
89 0
html+css实战179-快捷导航布局-内容
好客租房140-长列表性能优化(可视区域渲染)
好客租房140-长列表性能优化(可视区域渲染)
76 0
好客租房140-长列表性能优化(可视区域渲染)
|
Web App开发 JavaScript 前端开发
分享25个优秀的网站底部设计案例
  相对于网站头部来说,关注网站底部设计的人很少。我们平常也能碰到有些网站的底部设计得很漂亮,给网站的呈现来一个完美的结尾。这篇文章收集了25个优秀的网站底部设计案例,一起欣赏。 me & oli La Bubbly Poogan’s Porch GiftRocket Li...
1420 0