渲染瀑布流也容易,Flutter手绘瀑布流第二篇
2023-12-02 00:42:17
在上一篇文章中,我们已经实现了Flutter中的一个瀑布流。但是,它存在一个明显的缺陷,那就是它只能支持Cupertino风格的小部件。
这对于一些想要在应用程序中使用Material风格的小部件的用户来说,是一个很大的限制。因此,在本文中,我们将探讨如何使用RenderObject来实现Flutter中的瀑布流。
使用RenderObject来实现瀑布流具有几个优点。首先,它允许我们使用Flutter原生渲染机制来渲染瀑布流的每一行数据。这使得瀑布流更加高效和灵活。
其次,它允许我们使用任何类型的Flutter小部件来填充瀑布流。这使得瀑布流更加通用,可以用于各种各样的应用程序。
渲染瀑布流
为了使用RenderObject来渲染瀑布流,我们需要创建一个新的RenderObject子类。这个子类将负责测量、布局和绘制瀑布流的每一行数据。
在我们的例子中,我们将创建一个名为SliverFlowDelegate
的新RenderObject子类。这个子类将负责测量、布局和绘制瀑布流的每一行数据。
import 'package:flutter/rendering.dart';
class SliverFlowDelegate extends RenderSliver {
SliverFlowDelegate({
required this.itemBuilder,
required this.itemCount,
required this.crossAxisSpacing,
required this.mainAxisSpacing,
required this.childSize,
});
final IndexedWidgetBuilder itemBuilder;
final int itemCount;
final double crossAxisSpacing;
final double mainAxisSpacing;
final Size childSize;
@override
void performLayout() {
double contentHeight = 0.0;
double crossAxisOffset = 0.0;
double mainAxisOffset = 0.0;
for (int i = 0; i < itemCount; i++) {
final BoxConstraints constraints = BoxConstraints.tight(childSize);
final SliverMultiBoxAdaptorElement child = childManager.createChild(i, constraints);
child.layout(constraints);
final double childHeight = child.size.height;
final double childWidth = child.size.width;
if (crossAxisOffset + childWidth > constraints.maxWidth) {
crossAxisOffset = 0.0;
mainAxisOffset += childHeight + mainAxisSpacing;
}
child.geometry = SliverGeometry(
scrollOffset: mainAxisOffset,
crossScrollOffset: crossAxisOffset,
paintExtent: childHeight,
maxPaintExtent: childHeight,
);
crossAxisOffset += childWidth + crossAxisSpacing;
contentHeight += childHeight + mainAxisSpacing;
}
geometry = SliverGeometry(
scrollExtent: contentHeight,
maxScrollExtent: contentHeight,
);
}
@override
void paint(PaintingContext context, Offset offset) {
for (int i = 0; i < itemCount; i++) {
final BoxConstraints constraints = BoxConstraints.tight(childSize);
final SliverMultiBoxAdaptorElement child = childManager.createChild(i, constraints);
child.paint(context, offset);
final double childHeight = child.size.height;
final double childWidth = child.size.width;
if (crossAxisOffset + childWidth > constraints.maxWidth) {
crossAxisOffset = 0.0;
mainAxisOffset += childHeight + mainAxisSpacing;
}
offset = offset.translate(0.0, childHeight + mainAxisSpacing);
}
}
}
SliverFlowDelegate
类具有以下属性:
itemBuilder
: 一个函数,它返回瀑布流的每一行数据对应的部件。itemCount
: 瀑布流中的数据项总数。crossAxisSpacing
: 瀑布流中相邻列之间的间距。mainAxisSpacing
: 瀑布流中相邻行之间的间距。childSize
: 瀑布流中每一行数据对应的部件的大小。
SliverFlowDelegate
类还具有以下方法:
performLayout()
: 该方法测量和布局瀑布流的每一行数据。paint()
: 该方法绘制瀑布流的每一行数据。
使用SliverFlowDelegate创建瀑布流
为了使用SliverFlowDelegate
类创建瀑布流,我们需要创建一个新的SliverPersistentHeaderDelegate
子类。这个子类将负责将SliverFlowDelegate
类包装成一个SliverPersistentHeader
对象。
import 'package:flutter/material.dart';
class SliverFlowPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
SliverFlowPersistentHeaderDelegate({
required this.childSize,
required this.itemBuilder,
required this.itemCount,
required this.crossAxisSpacing,
required this.mainAxisSpacing,
});
final Size childSize;
final IndexedWidgetBuilder itemBuilder;
final int itemCount;
final double crossAxisSpacing;
final double mainAxisSpacing;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return SliverFlowDelegate(
childSize: childSize,
itemBuilder: itemBuilder,
itemCount: itemCount,
crossAxisSpacing: crossAxisSpacing,
mainAxisSpacing: mainAxisSpacing,
);
}
@override
double get maxExtent => 10000.0;
@override
double get minExtent => 10000.0;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}
SliverFlowPersistentHeaderDelegate
类具有以下属性:
childSize
: 瀑布流中每一行数据对应的部件的大小。itemBuilder
: 一个函数,它返回瀑布流的每一行数据对应的部件。itemCount
: 瀑布流中的数据项总数。crossAxisSpacing
: 瀑布流中相邻列之间的间距。mainAxisSpacing
: 瀑布流中相邻行之间的间距。
SliverFlowPersistentHeaderDelegate
类还具有以下方法:
build()
: 该方法构建瀑布流。maxExtent
: 返回瀑布流的最大高度。minExtent
: 返回瀑布流的最小高度。shouldRebuild()
: 该方法决定瀑布流是否需要重建。
使用SliverFlowPersistentHeaderDelegate创建瀑布流
为了使用SliverFlowPersistentHeaderDelegate
类创建瀑布流,我们需要创建一个新的CustomScrollView
对象。这个对象将负责滚动瀑布流。
import 'package:flutter/material.dart';
class SliverFlow extends StatelessWidget {
SliverFlow({
required this.childSize,
required this.itemBuilder,
required this.itemCount,
required this.crossAxisSpacing,
required this.mainAxisSpacing,
});
final Size childSize;
final IndexedWidgetBuilder itemBuilder;
final int itemCount;
final double crossAxisSpacing;
final double mainAxisSpacing;
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverPersistentHeader(
delegate: SliverFlowPersistentHeaderDelegate(
childSize: childSize,
itemBuilder: itemBuilder,
itemCount: itemCount,
crossAxisSpacing: crossAxisSpacing,
mainAxisSpacing: mainAxisSpacing,
),
),
],
);
}
}
SliverFlow
类具有以下属性:
childSize
: 瀑布流中每一行数据对应的部件的大小。itemBuilder
: 一个函数,它返回瀑布流的每一行数据对应的部件。itemCount
: 瀑布流中的数据项总数。crossAxisSpacing
: 瀑布流中相邻列之间的间距。mainAxisSpacing
: 瀑布流中相邻行之间的间距。
SliverFlow
类还具有以下方法:
build()
: 该方法构建瀑布流。
使用SliverFlow创建瀑布流
为了使用SliverFlow
类创建瀑布流,我们需要创建一个新的MaterialApp
对象。这个对象将负责启动应用程序。
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: SliverFlow(
childSize: Size(200.0, 200