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

github传送门


目录

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

前言

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

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

效果图

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


快速上手

先来实操一下, 看看从默认的滚动模板(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:

删除重复部分:

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


AppBarLayout滚动方式

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

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

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

  • 那我现在用的是app:layout_scrollFlags="scroll|exitUntilCollapsed", 效果大家也见过了.
  • 喜闻乐见的吸附效果, app:layout_scrollFlags="scroll|snap", 例如, 还剩下25%没滚完, 松手就自己滚出去; 如果还有75%没滚完, 松手直接全部显示. 但是我感觉体验不好, 会让人有着操作不灵敏的错觉.

  • 快速返回, 就是把滚出去的部分快速显示出来, 可以对比之前的返回速度来看: app:layout_scrollFlags="scroll|enterAlways"

  • 对比快速返回来看, 这个相对柔和一些, 可以理解为二段式的快速返回, 总之就是返回没有enterAlways那么迅速: app:layout_scrollFlags="scroll|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填入.


最后

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

github传送门


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值