Android ListView功能扩展,实现高性能的瀑布流布局,android开发项目实例记事本

可以看到,这是一个非常普通的 ListView,每个 ListView 的子 View 里面有一张图片,一段文字,还有一个按钮。文字的长度是随机生成的,因此每个子 View 的高度也各不相同。那么我们现在就来对 ListView 进行扩展,让它拥有瀑布流展示的能力。

首先,我们打开 AbsListView 这个类,在里面添加如下所示的几个全局变量:

protected int mColumnCount = 2;

protected ArrayList[] mColumnViews = new ArrayList[mColumnCount];

protected Map<Integer, Integer> mPosIndexMap = new HashMap<Integer, Integer>();

其中 mColumnCount 表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在 XML 里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews 创建了一个长度为 mColumnCount 的数组,数组中的每个元素都是一个泛型为 View 的 ArrayList,用于缓存对应列的子 View。mPosIndexMap 则是用于记录每一个位置的子 View 应当放置在哪一列当中。

接下来让我们回忆一下,ListView 最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是 fillDown() 和 fillUp() 方法,而这两个方法的触发点都是在 fillGap() 方法当中的,fillGap() 方法又是由 trackMotionScroll() 方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用 fillGap() 方法来进行填充。那么,trackMotionScroll() 方法也许就应该是我们开始着手修改的地方了。

这里我们最主要的就是修改对于子 View 进入屏幕判断的时机,因为原生的 ListView 只有一列内容,而瀑布流布局将会有多列内容,所以这个时机的判断算法也就需要进行改动。那么我们先来看一下原先的判断逻辑,如下所示:

final int firstTop = getChildAt(0).getTop();

final int lastBottom = getChildAt(childCount - 1).getBottom();

final Rect listPadding = mListPadding;

final int spaceAbove = listPadding.top - firstTop;

final int end = getHeight() - listPadding.bottom;

final int spaceBelow = lastBottom - end;

这里 firstTop 表示屏幕中第一个元素顶边的位置,lastBottom 表示屏幕中最后一个元素底边的位置,然后 spaceAbove 记录屏幕第一个元素顶边到 ListView 上边缘的距离,spaceBelow 记录屏幕最后一个元素底边到 ListView 下边缘的距离。最后使用手指在屏幕上移动的距离和 spaceAbove、spaceBelow 进行比较,来判断是否需要调用 fillGap() 方法,如下所示:

final int absIncrementalDeltaY = Math.abs(incrementalDeltaY);

if (spaceAbove < absIncrementalDeltaY || spaceBelow < absIncrementalDeltaY) {

了解了原先的工作原理之后,我们就可以来思考一下怎么将这个逻辑改成适配瀑布流布局的方式。比如说目前 ListView 中有两列内容,那么获取屏幕中的第一个元素和最后一个元素其实意义是不大的,因为在有多列内容的情况下,我们需要找到的是最靠近屏幕上边缘和最靠近屏幕下边缘的元素,因此这里就需要写一个算法来去计算 firstTop 和 lastBottom 的值,这里我先把修改后的 trackMotionScroll() 方法贴出来,然后再慢慢解释:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值