分享一个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. 不错位的java .class 反编译工具推荐

    我们经常会反编译看一些class文件,但是反编译出来的文件里面会有很多杂乱的东西 一直以来都是用的idea来反编译的,只要把class文件往里面一拖就行了 这么用没问题,用来看看源码什么的都OK 但是 ...

  2. python实现tail -f功能

    这篇文章最初是因为reboot的群里,有人去面试,笔试题有这个题,不知道怎么做,什么思路,就发群里大家讨论 我想了一下,简单说一下我的想法吧,当然,也有很好用的pyinotify模块专门监听文件变化, ...

  3. 菜鸟学Java(二十一)——如何更好的进行单元测试——JUnit

    测试在软件生命周期中的重要性,不用我多说想必大家也都非常清楚.软件测试有很多分类,从测试的方法上可分为:黑盒测试.白盒测试.静态测试.动态测试等:从软件开发的过程分为:单元测试.集成测试.确认测试.验 ...

  4. HHH

    https://data-artisans.com/flink-forward/resources/alibabas-common-algorithm-platform-on-flink https: ...

  5. wireshark in ubuntu

    安装 sudo apt-get install wiresharksudo dpkg-reconfigure wireshark-commonsudo usermod -a -G wireshark ...

  6. 一、图解Java中String不可变性

    这里有一堆例子来说明Java的String的不可变性. 1.声明一个String String s = "abcd"; s 变量保存string对象的引用,下面的箭头解释成保存了哪 ...

  7. linux管道命令学习(一)

    继续看鸟哥私房菜,看一直很想弄懂的管道命令(pipe).第一次知道管道这个词还是在学django的时候,模板里的过滤器很像这里的管道.管道就是将输出在标准输出中的信息一次次处理最终打印在标准输出中,所 ...

  8. mysql关联更新update

    https://blog.csdn.net/babyfish13/article/details/78082844 ****************************************** ...

  9. SQL Server 2008 R2升级到SQL Server 2012 SP1

    1.建议对生产环境对的数据库升级之前做好备份,以防不测. 2.从SQL Server 2008 R2 升级到SQL Server 2012 SP1,需要先安装SQL Server 2008 R2 的S ...

  10. hdu1839(二分+优先队列,bfs+优先队列与spfa的区别)

    题意:有n个点,标号为点1到点n,每条路有两个属性,一个是经过经过这条路要的时间,一个是这条可以承受的容量.现在给出n个点,m条边,时间t:需要求在时间t的范围内,从点1到点n可以承受的最大容量... ...