PinnedListView分析一
分享一个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分析一的更多相关文章
- PinnedListView分析二
在PinnedListView分析一中还有一些细节在本文做一个补充,主要是view的绘制: 一个view在真正被绘制都是通过canvas来做,在ViewGroup内的z子view,一般再次此之前,还需 ...
- alias导致virtualenv异常的分析和解法
title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...
- 火焰图分析openresty性能瓶颈
注:本文操作基于CentOS 系统 准备工作 用wget从https://sourceware.org/systemtap/ftp/releases/下载最新版的systemtap.tar.gz压缩包 ...
- 一起来玩echarts系列(一)------箱线图的分析与绘制
一.箱线图 Box-plot 箱线图一般被用作显示数据分散情况.具体是计算一组数据的中位数.25%分位数.75%分位数.上边界.下边界,来将数据从大到小排列,直观展示数据整体的分布情况. 大部分正常数 ...
- 应用工具 .NET Portability Analyzer 分析迁移dotnet core
大多数开发人员更喜欢一次性编写好业务逻辑代码,以后再重用这些代码.与构建不同的应用以面向多个平台相比,这种方法更加容易.如果您创建与 .NET Core 兼容的.NET 标准库,那么现在比以往任何时候 ...
- UWP中新加的数据绑定方式x:Bind分析总结
UWP中新加的数据绑定方式x:Bind分析总结 0x00 UWP中的x:Bind 由之前有过WPF开发经验,所以在学习UWP的时候直接省略了XAML.数据绑定等几个看着十分眼熟的主题.学习过程中倒是也 ...
- 查看w3wp进程占用的内存及.NET内存泄露,死锁分析
一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...
- ZIP压缩算法详细分析及解压实例解释
最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
随机推荐
- Unity Shaders and Effects Cookbook (4-1)(4-2)静态立方体贴图的创建与使用
開始学习第4章 - 着色器的反射 看完了1.2节,来记录一下.反射主要是利用了 Cubemap 立方体贴图. 认识Cubemap 立方体贴图.就如同名字所说.在一个立方体上有6张图.就这样觉得吧. 假 ...
- 2-7-集合运算(A-B)∪(B-A)-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版
课本源码部分 第2章 线性表 - 集合运算(A-B)∪(B-A) ——<数据结构>-严蔚敏.吴伟民版 ★有疑问先阅读★ 源码使用说明 链接☛☛☛ <数据结构-C语言 ...
- Vue.js使用-组件(下篇)
上一节,我们定义了组件的基本使用,下面我们看看组件其他的一些特性. 1.组件作用域 同时在Vue对象和组件中定义一个属性,显示结果是怎样的呢? <!DOCTYPE html> <ht ...
- 每日英语:China's Wistful Wen Gets His Wish
As his term as premier was drawing to a close, Wen Jiabao reflected wistfully on some of the goals h ...
- HTTP 代理服务器技术选型之旅
HTTP 代理服务器技术选型之旅 背景 长期以来,贴吧开发人员多,业务耦合大,需求变化频繁,因此容易产生 bug.而我所负责的广告相关业务,和 UI 密切相关,一旦因为某种原因(甚至是被别人改了代码) ...
- python中redis查看剩余过期时间以及用正则通配符批量删除key的方法
# -*- coding: utf-8 -*- import redis import datetime ''' # 1. redis设置过期时间的两种方式 expire函数设置过期时间为10秒.10 ...
- [DIOCP3/MyBean/QDAC开源项目] DataModule-DB例子基于MyBean的插件实例<三层数据库方案>
[说明] 这个例子答应大家很久了,一直没有时间弄,现在正式结合MyBean插件可以很方便的在客户端共享操作连接,执行数据库的各项工作,屏蔽了底层的通信解码器编码等工作,直接传递Variant,给了开发 ...
- Openfire注册流程代码分析
Openfire注册流程代码分析 一.客户端/服务端注册用户流程 经过主机连接消息确认后,客户端共发送俩条XML完成注册过程.服务器返回两条XML. 注:IQ消息节点用于处理用户的注册.好友.分组.获 ...
- User-Defined-Literal自定义字面量
c++支持多种内置类型的字面量,比如: 123u // unsigned int 1.0 // double 1.6f // float 'a' // char 4ULL // unsigned lo ...
- C++中虚函数的作用是什么?它应该怎么用呢?
虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...