分享一个Android控件,PinnedHeaderListView , 大致是像图钉一样,能够固定显示一个头部在ListView的顶部,类似于Android原版通讯录中联系人按照字母分组排列, 这个东西其实出来很久了,今天仔细阅读了源码,再次做一个分享。

效果预览

下面的图左边是预览的效果,右边则是项目涉及的重要类。

原理概述   

  • 为了便于分析,我们先做一些命名的约定。这个List继承自ListView,灰色半透明item暂且称其为section view,而其他的白色条目暂称为item view,当section view滑动至顶部后将停留在顶部,而白色的item view可以继续上划消失,这里固定后的section view 我们暂时称其为current header view,注意它实际上不存在于ListView内部,而是实时可变的画在顶部的view。
  • 通过滑动事件监听,在onScroll()内设置current header view的内容和位置的偏移量,在每次滑动事件的结尾触发lisview进行重绘,这时再dispatchDraw()中通过canvas来绘制视图。
  • 与之配套的adapter则实现一些具体的view的实例化操作和区分不同的view,比如section view和item view,以及这两种view各自的view type处理等等。

实现分析

我们已经知道他的实现机制,现在先来具体分析一下的内部实现,涉及到的类可以在上面的预览图中看到,主要是PinnedHeaderListView 和SectionedBaseAdapter以及相关接口定义和实现。

  • PinnedHeaderListView

下面是它定义的一些重要成员,具体作用我已经在后面加了注释, 其中的mCurrentHeader即为current header view。

private View mCurrentHeader;// pinned top header view

private int mCurrentHeaderViewType = 0;

private float mHeaderOffset;// offset for pinned header view

private boolean mShouldPin = true;//default to enable pinned header view

在PinnedHeaderListView内部他继承了ListView并实现了OnScrollListener接口,现在我们先分析onScroll里面所做的事情,大致可以分为四块:

1.外部on scroll的的触发,

首先是重载了ListView得setOnScrollListener()方法,通过成员变量mOnScrollListener来引用外部设置的listener,然后再已经实现的OnScrollListener接口中调用mOnScrollListener,

这样一来我们任然可以在空间外部设置setOnScrollListener做其他的事情.

  2. 处理section view尚未接触顶部的状态

如果listview是空的或者我们通过setPinHeaders()使得listview不要pinned效果或则listview有设置header并且滑动时header还未完全出屏幕外,那么走下面的段代码,把current header view和他的offset置空,然后遍历所有子view设置为visible的状态,注意这一步是是必须的,因为在其他地方我们有可能会把子view设为invisible,而这个地方就是在设置pinned current header view的时候。

3. 复用或实例化pinned current header view

我已经在代码中加了注释,首先是计算出listview 原始header之外的item的索引起始位置,此时header如果存在,那么已经划出屏幕了,也就是当前第一个显示的位置减去header个数;根据这个item的position来获取对应的section view的position和view type,具体的代码实现在SectionBaseAdapter里面。接着是获取current header view的实例,根据view type和和当前的位置position是否变化,可能是复用的也可能是全新创建的

4. 遍历所有的section view设置visibility

现在从屏幕上可见的子section view开始遍历,计算出section view的顶部Y坐标,和pinned current header view的高度作比较,当section view向上滑动到开始与pinned current header view的区域相交时,我们计算出交叉的高度作为current header view的Y轴偏移量,继续向上滑动,当section view的顶部Y坐标小于0,也就是开始要划出屏幕时我们设置它为invisible,这样做的目的在于造成错觉,好像section view被定在了list view得顶部,实际上如果这里我们不把他设为invisible那么在demo运行时你将更清晰的发现原来向上滑动的section view其实一直在向上滑动。


最后我们需要调用 invalidate();来重绘界面,这样我们刚才更新的current header view 的偏移量就会在绘制的时候生效。

分析到这里我们对PinnedHeaderListView已经有了更深刻的理解,如果你发现思路有点跟不上下面的这张简略的流程图可能会有所帮助。

对与之配套的Adapter我将在下一篇文章在做分析…..

PinnedListView分析一的更多相关文章

  1. PinnedListView分析二

    在PinnedListView分析一中还有一些细节在本文做一个补充,主要是view的绘制: 一个view在真正被绘制都是通过canvas来做,在ViewGroup内的z子view,一般再次此之前,还需 ...

  2. alias导致virtualenv异常的分析和解法

    title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...

  3. 火焰图分析openresty性能瓶颈

    注:本文操作基于CentOS 系统 准备工作 用wget从https://sourceware.org/systemtap/ftp/releases/下载最新版的systemtap.tar.gz压缩包 ...

  4. 一起来玩echarts系列(一)------箱线图的分析与绘制

    一.箱线图 Box-plot 箱线图一般被用作显示数据分散情况.具体是计算一组数据的中位数.25%分位数.75%分位数.上边界.下边界,来将数据从大到小排列,直观展示数据整体的分布情况. 大部分正常数 ...

  5. 应用工具 .NET Portability Analyzer 分析迁移dotnet core

    大多数开发人员更喜欢一次性编写好业务逻辑代码,以后再重用这些代码.与构建不同的应用以面向多个平台相比,这种方法更加容易.如果您创建与 .NET Core 兼容的.NET 标准库,那么现在比以往任何时候 ...

  6. UWP中新加的数据绑定方式x:Bind分析总结

    UWP中新加的数据绑定方式x:Bind分析总结 0x00 UWP中的x:Bind 由之前有过WPF开发经验,所以在学习UWP的时候直接省略了XAML.数据绑定等几个看着十分眼熟的主题.学习过程中倒是也 ...

  7. 查看w3wp进程占用的内存及.NET内存泄露,死锁分析

    一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...

  8. ZIP压缩算法详细分析及解压实例解释

    最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...

  9. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

随机推荐

  1. shell - 常识

    一.用户登陆进入系统后的系统环境变量: $HOME 使用者自己的目录 $PATH 执行命令时所搜寻的目录 $TZ 时区 $MAILCHECK 每隔多少秒检查是否有新的信件 $PS1 在命令列时的提示号 ...

  2. Android 抓包并通过 Wireshark 分析

    分析 Android 中 app 的网络数据交互,需要在 Android 上抓包,常用工具为 tcpdump ,用 tcpdump 生成 Wireshark 识别的 pcap 文件,把 pcap 文件 ...

  3. 【Unity】5.2 天空盒

    分类:Unity.C#.VS2015 创建日期:2016-04-20 一.简介 Unity中的天空盒实际上是一种使用了特殊类型Shader的材质,这种类型的材质可以笼罩在整个游戏场景之外,并根据材质中 ...

  4. Why do people integrate Spark with TensorFlow even if there is a distributed TensorFlow framework?

    https://www.quora.com/Why-do-people-integrate-Spark-with-TensorFlow-even-if-there-is-a-distributed-T ...

  5. 解决myeclipse/eclipse创建或导入maven工程时引发的问题

    起因: 最近学习maven,按照教程把命令行创建的maven工程导入到eclipse/myeclipse,由于库中没有一些依赖包,所以在导入工程的时候开发工具自动下载依赖包.可是,由于天朝特殊环境的问 ...

  6. linux上的语音识别程序

    ubuntu下安装: $ sudo add-apt-repository ppa:hgneng/ekho $ sudo apt-get update $ sudo apt-get -y install ...

  7. python 三元表达式 if for 构建List 进阶用法

    1.简单的for...[if]...语句 Python中,for...[if]...语句一种简洁的构建List的方法,从for给定的List中选择出满足if条件的元素组成新的List,其中if是可以省 ...

  8. Effective Spark RDDs with Alluxio【转】

    转自:http://kaimingwan.com/post/alluxio/effective-spark-rdds-with-alluxio 1. 介绍 2. 引言 3. Alluxio and S ...

  9. pre 标签的使用注意事项

    .news-msg{ // padding: 5px; white-space: pre-wrap; word-wrap: break-word; font-family:'微软雅黑'; } < ...

  10. Spark中groupBy groupByKey reduceByKey的区别

    groupBy 和SQL中groupby一样,只是后面必须结合聚合函数使用才可以. 例如: hour.filter($"version".isin(version: _*)).gr ...