粘性无限列表
带有粘性标题的无限列表。
此包旨在实现
双向渲染无限列表,带有粘性页眉,不同于大多数
Dart Pub上的软件包。
支持各种页眉定位。还支持垂直和
水平滚动列表
它高度可定制,并且没有任何第三方依赖项或原生(Android/iOS)代码。
除了默认用法外,此包还公开了一些类,这些类
可以在需要时被覆盖。另外一些类可以在
Scrollable小部件中独立于InfiniteList容器使用。
此包使用CustomScrollView来执行滚动,并具有所有
Flutter提供的性能优势。
功能
- 无限列表中的粘性页眉
- 多向无限列表
- 粘性页眉位置的自定义
- 水平粘性列表支持
- 动态页眉构建于内容滚动之上
- 动态最小偏移量在内容滚动时计算
演示
入门
安装并导入包
import 'package:sticky_infinite_list/sticky_infinite_list.dart';
包公开InfiniteList、InfiniteListItem、StickyListItem、
StickyListItemRenderObject类
示例
简单示例
要开始使用带有粘性页眉的无限列表,
您需要创建一个带有指定构建器的InfiniteList实例。
无需指定任何附加配置即可使其正常工作
import 'package:sticky_infinite_list/sticky_infinite_list.dart';
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InfiniteList(
builder: (BuildContext context, int index) {
/// Builder requires [InfiniteList] to be returned
return InfiniteListItem(
/// Header builder
headerBuilder: (BuildContext context) {
return Container(
///...
);
},
/// Content builder
contentBuilder: (BuildContext context) {
return Container(
///...
);
},
);
}
);
}
}
状态
当调用最小偏移量回调或调用页眉构建器时,StickyState对象将作为参数传递
此对象描述粘性页眉的当前状态。
class StickyState<I> {
/// Position, that header already passed
///
/// Value can be between 0.0 and 1.0
///
/// If it's `0.0` - sticky in max start position
///
/// `1.0` - max end position
///
/// If [InfiniteListItem.initialHeaderBuild] is true, initial
/// header render will be with position = 0
final double position;
/// Number of pixels, that outside of viewport
///
/// If [InfiniteListItem.initialHeaderBuild] is true, initial
/// header render will be with offset = 0
///
/// For header bottom positions (or right positions for horizontal)
/// offset value also will be amount of pixels that was scrolled away
final double offset;
/// Item index
final I index;
/// If header is in sticky state
///
/// If [InfiniteListItem.minOffsetProvider] is defined,
/// it could be that header builder will be emitted with new state
/// on scroll, but [sticky] will be false, if offset already passed
/// min offset value
///
/// WHen [InfiniteListItem.minOffsetProvider] is called, [sticky]
/// will always be `false`. Since for min offset calculation
/// offset itself not defined yet
final bool sticky;
/// Scroll item height.
///
/// If [InfiniteListItem.initialHeaderBuild] is true, initial
/// header render will be called without this value
final double contentSize;
}
扩展配置
可用配置
除了开始使用的最少配置外。
InfiniteList允许您定义滚动列表渲染的配置
InfiniteList(
/// Optional parameter to pass ScrollController instance
controller: ScrollController(),
/// Optional parameter
/// to specify scroll direction
///
/// By default scroll will be rendered with just positive
/// direction `InfiniteListDirection.forward`
///
/// If you need infinite list in both directions use `InfiniteListDirection.multi`
direction: InfiniteListDirection.multi,
/// Min child count.
///
/// Will be used only when `direction: InfiniteListDirection.multi`
///
/// Accepts negative values only
///
/// If it's not provided, scroll will be infinite in negative direction
minChildCount: -100,
/// Max child count
///
/// Specifies number of elements for forward list
///
/// If it's not provided, scroll will be infinite in positive direction
maxChildCount: 100,
/// ScrollView anchor value.
anchor: 0.0,
/// Item builder
///
/// Should return `InfiniteListItem`
builder: (BuildContext context, int index) {
return InfiniteListItem(
//...
)
}
)
InfiniteListItem允许您为您的自定义指定更多选项。
InfiniteListItem(
/// See class description for more info
///
/// Forces initial header render when [headerStateBuilder]
/// is specified.
initialHeaderBuild: false,
/// Simple Header builder
/// that will be called once during List item render
headerBuilder: (BuildContext context) {},
/// Header builder, that will be invoked each time
/// when header should change it's position
///
/// Unlike prev method, it also provides `state` of header
/// position
///
/// This callback has higher priority than [headerBuilder],
/// so if both header builders will be provided,
/// [headerBuilder] will be ignored
headerStateBuilder: (BuildContext context, StickyState<int> state) {},
/// Content builder
contentBuilder: (BuildContext context) {},
/// Min offset invoker
///
/// This callback is called on each header position change,
/// to define when header should be stick to the bottom of
/// content.
///
/// If this method not provided or it returns `0`,
/// header will be in sticky state until list item
/// will be visible inside view port
minOffsetProvider: (StickyState<int> state) {},
/// Header alignment
///
/// Use [HeaderAlignment] to align header to left,
/// right, top or bottom side
///
/// Optional. Default value [HeaderAlignment.topLeft]
headerAlignment: HeaderAlignment.topLeft,
/// Scroll direction
///
/// Can be vertical or horizontal (see [Axis] class)
///
/// This value also affects how bottom or top
/// edge header positioned headers behave
scrollDirection: Axis.vertical,
);
演示
页眉对齐演示
水平滚动演示
反向无限滚动
当前包不支持CustomScrollView.reverse选项。
但是,通过定义anchor = 1可以获得相同的结果,
maxChildCount = 0。这样,视口中心将固定
在底部,正面列表将不渲染任何内容。
此外,您可以将headerAlignment指定到任何一侧。
import 'package:sticky_infinite_list/sticky_infinite_list.dart';
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InfiniteList(
anchor: 1.0,
direction: InfiniteListDirection.multi,
maxChildCount: 0,
builder: (BuildContext context, int index) {
/// Builder requires [InfiniteList] to be returned
return InfiniteListItem(
headerAlignment: HeaderAlignment.bottomLeft,
/// Header builder
headerBuilder: (BuildContext context) {
return Container(
///...
);
},
/// Content builder
contentBuilder: (BuildContext context) {
return Container(
///...
);
},
);
}
);
}
}
演示
有关更多信息,请参阅
示例项目
可覆盖
在大多数情况下,仅使用InfiniteListItem就足够了
但在某些情况下,您可能需要为
每个项目添加额外功能。
幸运的是,您可以扩展和覆盖基类InfiniteListItem
/// Generic `I` is index type, by default list item uses `int`
class SomeCustomListItem extends InfiniteListItem<I> {
/// Header alignment
///
/// Supports all sides alignment, see [HeaderAlignment] for more info
///
/// By default [HeaderAlignment.topLeft]
final HeaderAlignment headerAlignment;
/// Let item builder know if it should watch
/// header position changes
///
/// If this value is `true` - it will invoke [buildHeader]
/// each time header position changes
@override
bool get watchStickyState => true;
/// Let item builder know that this class
/// provides header
///
/// If it returns `false` - [buildHeader] will be ignored
/// and never called
@override
bool get hasStickyHeader => true;
/// This methods builds header
///
/// If [watchStickyState] is `true`,
/// it will be invoked on each header position change
/// and `state` option will be provided
///
/// Otherwise it will be called only once on initial render
/// and each header position change won't invoke this method.
///
/// Also in that case `state` will be `null`
@override
Widget buildHeader(BuildContext context, [StickyState<I> state]) {}
/// Content item builder
///
/// This method invoked only once
@override
Widget buildContent(BuildContext context) => {}
/// Called during init state (see Statefull widget [State.initState])
///
/// For additional information about Statefull widget `initState`
/// lifecycle - see Flutter docs
@protected
@mustCallSuper
void initState() {}
/// Called during item dispose (see Statefull widget [State.dispose])
///
/// For additional information about Statefull widget `dispose`
/// lifecycle - see Flutter docs
@protected
@mustCallSuper
void dispose() {}
}
需要更多覆盖?..
如果您在此类覆盖方面遇到任何问题,
请创建一个问题
除了列表项覆盖之外,还要在InfiniteList构建器中使用,
您也可以独立使用此包公开的StickyListItem。
此类使用Stream来通知其父级关于页眉位置的变化
它还需要在Scrollable小部件和Viewport中渲染,
因为它订阅了滚动事件并计算位置
相对于Viewport坐标(请参阅StickyListItemRenderObject类
了解更多信息)
例如
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: height,
color: Colors.lightBlueAccent,
child: Placeholder(),
),
StickyListItem<String>(
header: Container(
height: 30,
width: double.infinity,
color: Colors.orange,
child: Center(
child: Text('Sticky Header')
),
),
content: Container(
height: height,
color: Colors.blueAccent,
child: Placeholder(),
),
itemIndex: 'single-child-index',
),
Container(
height: height,
color: Colors.cyan,
child: Placeholder(),
),
],
),
);
}
此代码将渲染单个子滚动
带有3个小部件。中间一个 - 带有粘性页眉的项目。
演示
有关更复杂的示例,请查看“单个示例”页面
在示例项目中
GitHub
https://github.com/TatsuUkraine/flutter_sticky_infinite_list