一套Flutter混排瀑布流解决方案

本文介绍了在Flutter中实现混排瀑布流布局的解决方案,针对现有开源库的不足,提出了一套支持普通卡片和横条卡片混排的布局策略。详细解析了布局的尺寸计算和位置计算过程,包括网格布局和瀑布流布局的对比,并探讨了内存回收和性能优化措施。该方案已应用于闲鱼项目,未来有望支持更多列数的混排和性能提升。
摘要由CSDN通过智能技术生成

背景

流式布局,这是一种当前无论是前端,还是Native都比较流行的一种页面布局。特别是对于商品这样的Feeds流,无论是淘宝,京东,美团,还是闲鱼。都基本上以多列瀑布流进行呈现,容器列数固定,然后每个卡片高度不一,形成参差不齐的多栏布局。

对于Native来说,无论是iOS还是Android,CollectionView和RecyclerView都能满足我们的绝大部分场景了。不过目前闲鱼很多业务场景都是在Flutter上进行实现的,当时Flutter官方只提供了ListView和GridView的实现,没有对瀑布流进行支持。

目前社区中有两个开源的解决方案,分别是WaterFallFlow和FlutterStaggeredGridView。但是在闲鱼的场景中都有一些无法满足的痛点。前者无法支持RecyclerView中StaggeredGridLayoutManager中setFullSpan这样的横跨全屏的横条卡片混排能力能力,后者在不提前预设置卡片高度的情况下有比较严重的性能问题,以及在多Sliver的场景下会有滚动错误的功能性问题。而在目前闲鱼的业务中,无论是搜索结果还是首页的同城页面,都会有混排瀑布流的需求。

所以我们决定参考RecyclerView中StaggeredGridLayoutManager的布局思路实现一套支持普通流式卡片和横跨全屏的横条卡片混排的流式布局,如图所示:

原理分析与布局流程

其实瀑布流布局和ListView和GridView一样,就是按照不同的策略将多个卡片进行尺寸计算和位置计算,然后将它们排列到一起,组成一个超过一屏,可滚动的布局。所以整个布局策略包括两个过程,首先是对卡片进行尺寸计算,计算结果决定了卡片在滚动布局中的大小。然后卡片进行位置计算,计算结果决定了卡片在滚动布局中的坐标。有了大小和坐标,就可以完成整个滚动容器的布局。下面我会对网格布局(GridView)和瀑布流布局(FlowView)的布局策略进行一个对比,让大家能更清楚的了解布局过程的细节。

Flutter中网格布局整个布局的源码都在flutter/lib/src/rendering/sliver_grid.dart的performLayout方法中,我们下面跟着源码来分析一下整个布局流程。感兴趣的同学也可以结合源码食用本文,风味更佳。

网格布局

尺寸计算过程

我们先来分析一下网格布局的卡片尺寸计算过程。这是一个GridView的常用初始化参数,我省略了一些和尺寸计算无关的参数。

GridView.count({
  @required int crossAxisCount,
  double childAspectRatio = 1.0,
})

影响布局的参数其实就是crossAxisCount(列数)和childAspectRatio(卡片纵横比)。有了这两个参数其实卡片的尺寸就很好计算了,首先先用crossAxisCount来对屏幕宽度进行等分,确定卡片的宽度,然后我们再根据这个childAspectRatio参数来计算得到卡片的高度。网格布局的卡片尺寸就可以确定下来了。计算过程如图所示:

位置计算过程

在端侧,因为一个滚动容器中的卡片数量可能会非常大,所以我们不可能对所有的卡片都进行布局,内存和运算时间都是无法接受的。我们只会布局在屏幕中以及缓存区里的卡片,之外的卡片我们会进行回收。等用户向下滑动的时候,把屏幕下方的卡片创建并布局,然后把已经划出屏幕的卡片进行回收。向上滑动的过程也是一样。所以我们会对从上到下和从下到上的位置计算过程进行分析。

我们先分析从上到下布局的过程。对于网格布局来说,每一个卡片的宽度和高度都是在位置计算流程开始之前就可以提前计算得出的。我们暂且把每个卡片的左上角叫做布局坐标点,我们来分析一下网格布局中这个坐标如何计算得出。

我们先来计算一下纵坐标,我们用卡片的index对crossAxisCount进行整除,然后再用结果乘上卡片的高度

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值