返回

Flutter 瀑布流通用方案:深度解析与最佳实战

IOS

引述

俗话说,没有最好的方案,唯有最合适的方案。此话尤其适用于瀑布流场景。Flutter 的原生控件中并没有提供瀑布流组件,而市面上琳琅满目、宣称通用的瀑布流方案往往局限于特定场景,难以大规模推广。

本文将带领读者踏上 Flutter 瀑布流探索之旅,全面剖析其原理和设计思路,并逐步解析一个在闲鱼商品详情页场景下已经大规模落地的瀑布流方案。

剖析瀑布流

瀑布流是一种特殊的流式卡片展示形式,其形态灵感源于瀑布。瀑布流卡片高度不等,纵向排列,排列规则符合一定的算法,以保证瀑布流整体有序可控,富有视觉美感。

瀑布流的核心在于其独特的排列算法,它保证了卡片按列均匀有序地填充,无论瀑布流中有几列,无论卡片数量是多是少。该算法本质上是一种贪心策略,选择每一列中高度最小的卡片进行填充。

Flutter 瀑布流方案演进

早期,Flutter 中并没有原生的瀑布流组件。要满足瀑布流诉求,需要进行大量的定制开发,在 ListView 控件基础上进行封装,并结合 Sliver 体系和 Masonry 布局进行瀑布流的排列。

然而,受限于 Sliver 体系和 Masonry 布局的特性,此种方案在性能和扩展性上均有缺陷。特别是,在瀑布流卡片数量较多且卡片高度差异较大时,其性能表现尤为堪忧。

闲鱼通用瀑布流方案

为满足闲鱼内部众多业务对瀑布流的需求,我们沉淀出一套通用瀑布流方案,其核心思路如下:

  1. 布局模型抽象:我们剥离出瀑布流的排列规则,将其抽象为一个通用的瀑布流模型,解耦了瀑布流的排列逻辑和界面展示逻辑,提高了方案的扩展性。

  2. Canvas 布局:我们采用 Canvas 布局,跳过 Flutter 的渲染流水线,获得了原生的像素级渲染性能,解决了 ListView 嵌套 Sliver 布局下的性能问题。

  3. 异步栅格化:瀑布流卡片的高度计算和摆放逻辑是瀑布流方案中耗时最长的部分。我们将瀑布流的卡片摆放逻辑异步到栅格化线程,避免阻塞主线程。

  4. 性能优化:在多个场景下,我们针对瀑布流方案进行了大量的性能优化,例如:缓存卡片高度、按需计算瀑布流宽度等。

实战指引

下面,我们将基于闲鱼通用瀑布流方案进行一个瀑布流组件的开发实战,帮助读者领略瀑布流方案的全貌。

  1. 引入瀑布流库
import 'waterfall_flow.dart';
  1. 定义瀑布流模型
// 瀑布流模型:瀑布流卡片的尺寸信息数据结构
class WaterfallFlowModel {
  /// 卡片在第几列
  int columnIndex;

  /// 卡片高度
  double itemHeight;

  /// 卡片在列中的偏移量(从上到下)
  double itemOffset;
}
  1. 瀑布流组件
class WaterfallFlow extends StatelessWidget {
  // 构造方法省略 ...

  @override
  Widget build(context) {
    // 瀑布流模型
    var waterfallFlowModel = WaterfallFlowModel();

    return CustomMultiChildLayout(
      layoutCallback: (size, children) {
        //瀑布流排列逻辑
        //省略
        return waterfallFlowModel;
      }
      childCount: children.length,
      childSpec: WaterfallFlowChildSpec(),
    );
  }
}

总结

Flutter 瀑布流方案是 Flutter 布局体系中一块重要的拼图,它弥补了 Flutter 原生控件的不足,为开发者提供了灵活多变、性能优异的瀑布流展示方案。

闲鱼的通用瀑布流方案历经了多个版本的演进,其核心在于将瀑布流的排列逻辑抽象为一个通用的模型,并辅以 Canvas 布局和异步栅格化等优化手段,获得了跨场景的普适性和高性能。

我们鼓励广大开发者基于本方案进行进一步的探索和拓展,共同为 Flutter 的生态建设添砖加瓦。