ListView或者RecyclerView滚动时隐藏Toolbar (1)

今天我打算写一篇博文给大家介绍Google+ App的一个酷炫效果——向上/向下滚动ListView/RecyclerView时,Toolbar和FAB(屏幕右下方的小按钮)会隐藏/出现。这个效果也被Google视为符合 Material Design 规范的效果哦,详情参见: Material Design Checklist 。

如果可以的话,我们希望当屏幕向下滚动时,App的Toolbar和FAB将离开屏幕,从而在垂直方向上为可显示区域腾出更大的空间来显示我们的内容。而当我们的屏幕向上滚动时,App的Toolbar和FAB会再次出现。

我们做出来的最终效果应该是下面这样的:

在这篇博文的讲解中,我们将会用RecyclerView作为我们的list,但这不代表其他可滚动的容器就不能实现这样的效果了,只是其他的可滚动容器(如:ListView)需要要多花一些功夫才能实现这个效果。那么我们要怎么去实现呢?我想到了两个办法:

对list容器加一个Padding对list容器加一个Header

就我个人而言,我更想用第二种方法去实现,因为在设计代码的过程中我发现:为RecyclerView添加Header会产生几个问题,这给了我很好的机会去思考如何解决它,与此同时,在这个思考和解决问题的过程中我还能学习到更多的知识,何乐而不为呢?不过我还是会给大家简要地介绍如何使用第一种方法实现的啦!

那就让我们开始今天的讲解吧!

首先,我们需要创建一个工程和添加必要的工具库:

接着我们需要定义 styles.xml ,以确保我们的App没有添加Actionbar(因为我们将会使用Toolbar),同时我们App的设计风格要符合Google的 Material Design 规范。

最后我们就要创建我们activity中显示的布局:

事实上,我们只需要一个简单的布局,其中包含了:RecyclerView,Toolbar和ImageButton。但需要注意的是:我们需要把它们放在一个FrameLayout里,否则当我们隐藏Toolbar时list的上方将会出现一个空白区域,这显然不会是我们想要的效果。我们理想的效果应该是:当Toolbar被隐藏,list能在屏幕的可见区域中显示出一整个列表,而这就需要通过使Toolbar覆盖在RecycleView上面来实现。

接着来看看我们MainActivity代码吧:

就像你看到的那样,这是一个只重写了OnCreate()方法,非常非常非常简单的Activity。而且OnCreate()方法也只做了下面三件事情:

为了在list中显示出内容,我们现在就要为RecyclerView创建一个Adapter啦。但在此之前,我们应该为我们list中的item添加相应的子布局以及对应的ViewHolder:

list的每一个item只需要一个text用来显示文字,非常简单!

那RecyclerAdapter该怎么实现呢:

就像你看到的这样,这是一个非常普通的RecycleView.Adapter,没有任何特别的地方,是不是感觉被骗了呐 23333~(如果你想要了解更多有关RecyclerView知识,我强烈建议你去看大牛 Mark Allison’s 巨巨写的这些优秀文章 series of posts)

经过上面的努力,我们已经把车子的小零件组装的七七八八啦,是时候让小车子上路跑一跑,展现真正的技术了!

WTF,谁能告诉我这是什么鬼……?

我相信只要不是瞎子都会发现,App的Toolbar竟然把我们的item挡住了!!!或许部分机智的小伙伴已经发现了问题所在:出现这样的问题是因为我们在activity_main.xml里使用了FrameLayout,正是FrameLayout导致了这样的问题,而这就是我开头所提到的问题之一了。

第一个解决办法是为我们的RecyclerView添加一个PaddingTop,并将PaddingTop的值设置为Toolbar的高度。但有一个细节我们不能忽略,那就是RecyclerView会默认裁剪到子View的Padding区域,所以为了我们伟大的事业,我们必须把这个特性关掉。

经过这些修改之后,我们就能实现我们想要的效果,这就是我所说的第一种方法。但如我所说,我写这篇博文的目的,不仅仅只是教你实现这个效果,然后就完了。我想教给你实现同一个效果各种各样的方法,并且为你介绍其中的思想,让你接触到平常很难接触到的问题并教你如何解决它。有些方法固然会更加复杂(在本文中是为list添加一个Header),但你在实现过程中也能学到更多的知识,毕竟授人以鱼不如授人以渔嘛。

为RecycleView添加一个Header

要用第二种方法去实现这个效果,首先我们要做的就是稍微修改一下我们的Adapter:

下面是其实现原理:

我们需要定义一个常量来区分Recycler展现的item的类型。这里我需要为你介绍的是:RecyclerView是一个非常灵活的组件,RecyclerView 完全能实现你想要让list的item具有各种各样不同的布局的愿望,而此时,我们定义来区分item类型的常量就会被利用到。而这样的特性正是我们想要的——让Header成为RecyclerView的第一个item,显然这会与其余的item不一样。(第3-4行)

因而我们需要让Recycler知道它需要展示的子布局是什么类型的,在本文中我们用作类型区分的常量则是TYPE_ITEM和TYPE_HEADER。(第49-54行)

接着,我们需要修改onCreateViewHolder()和onBindViewHolder()方法,如果item的类型是TYPE_ITEM的话,使它们返回和绑定一个普通的item;如果item的类型是TYPE_HEADER的话,则返回Header。(第14-34行)

此外,由于我们的list并不仅仅只有普通的item,我们还在list中添加了Header,因此我们需要修改getItemCount()方法的返回值,让我们的返回值是普通item的总数量 + 1(第43-45行)

最后让我们来为Header布局创建一个layout和一个ViewHolder,,但出乎意料的是,我们需要为Header创建的layout和ViewHolder都非常简单,唯一需要注意的是:Header的高度必须和Toolbar的高度一致。

那么这样我们就把布局弄好啦~不信你看图!

所以总的来说,我们为RecyclerView添加了一个和Toolbar有相同高度的Header,而现在我们的Toolbar把header隐藏起来了(因为header现在是一个空的view),同时,我们所有的普通item都是可见的。那么现在就让我们来实现滚动时改变Toolbar和FAB的出现和隐藏吧!

滚动时控制Toolbar和FAB的出现和隐藏

为了实现这个效果,我们为RecyclerView再创建一个——OnScrollListener类就够了你敢信?

天才就是这样,终身努力,便是天才。

ListView或者RecyclerView滚动时隐藏Toolbar (1)

相关文章:

你感兴趣的文章:

标签云: