diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a46380..c85d60e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## [2.0.0] - 2020-07-02
+
+**Features**
+- refactor sticky item layout calculation
+- split alignment param on main and cross axis alignment
+- added padding property to `InfiniteListItem`
+- added relative positioning for header
+ [#19](https://github.com/TatsuUkraine/flutter_sticky_infinite_list/issues/19)
+
+**Release contains breaking changes, see MIGRATION.md for more details**
+
## [1.3.0] - 2020-04-28
**Features**
diff --git a/MIGRATION.md b/MIGRATION.md
new file mode 100644
index 0000000..2d4dbb9
--- /dev/null
+++ b/MIGRATION.md
@@ -0,0 +1,47 @@
+# Migration guide
+
+## Migration From v1.x.x to v2.x.x
+
+### Child count params
+
+In `InfiniteList` next params for max child count was renamed:
+- `minChildCount` was renamed to `negChildCount` and now it works with
+ positive numbers
+- `maxChildCount` was renamed to `posChildCount` and, as before, it
+ works with positive numbers
+
+### Header alignment
+
+Param `headerAlignment` in `InfiniteListItem` was replaced with 2
+params: `mainAxisAlignment` and `crossAxisAlignment`
+
+Main axis is placed with scroll direction: vertical or horizontal.
+
+With `mainAxisAlignment: HeaderMainAxisAlignment.start` and vertical
+scroll header will stick to the top edge, with horizontal scroll - to
+the left edge. Similar with `mainAxisAlignment:
+HeaderMainAxisAlignment.end` - bottom and right side respectively.
+
+`crossAxisAlignment` doesn't affect stick side. It just places header to
+the left or right side for the vertical scroll, and top or bottom - for
+horizontal scroll.
+
+New parameter was added for relative positioning: `positionAxis` which
+defines what direction should be used during layout - column or row.
+
+### List item layout
+
+Comparing to v1, v2 by default uses relative positioning.
+
+To make header overlay content use constructor `overlay`. It's available
+in both `InfiniteListItem` and `StickyListItem` widgets.
+
+### Initial header render
+
+In default constructor param `initialHeaderBuild` was removed.
+
+Since default constructor uses relative positioning, header is required
+to calculate appropriate item size.
+
+`initialHeaderBuild` is still available in `overlay` constructors and
+affects header render like it was before in v1.x.x
diff --git a/README.md b/README.md
index 6bccbf8..c97f375 100644
--- a/README.md
+++ b/README.md
@@ -32,9 +32,14 @@ benefits for performance that Flutter provides.
- dynamic header build on content scroll
- dynamic min offset calculation on content scroll
+## Migration guide
+
+If you using older MAJOR versions, please
+[visit this migration guide](https://github.com/TatsuUkraine/flutter_sticky_infinite_list/blob/master/MIGRATION.md)
+
## Demo
-
+
## Getting Started
@@ -88,6 +93,38 @@ class Example extends StatelessWidget {
}
```
+Or with header overlay content
+```dart
+
+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.overlay(
+ /// Header builder
+ headerBuilder: (BuildContext context) {
+ return Container(
+ ///...
+ );
+ },
+ /// Content builder
+ contentBuilder: (BuildContext context) {
+ return Container(
+ ///...
+ );
+ },
+ );
+ }
+ );
+ }
+}
+```
+
### State
When min offset callback invoked or header builder is invoked
@@ -163,21 +200,19 @@ InfiniteList(
/// If you need infinite list in both directions use `InfiniteListDirection.multi`
direction: InfiniteListDirection.multi,
- /// Min child count.
+ /// Negative max 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,
+ negChildCount: 100,
- /// Max child count
+ /// Positive max child count
///
/// Specifies number of elements for forward list
///
/// If it's not provided, scroll will be infinite in positive direction
- maxChildCount: 100,
+ posChildCount: 100,
/// ScrollView anchor value.
anchor: 0.0,
@@ -230,18 +265,32 @@ InfiniteListItem(
/// to define when header should be stick to the bottom of
/// content.
///
- /// If this method not provided or it returns `0`,
+ /// If this method returns `0`,
/// header will be in sticky state until list item
/// will be visible inside view port
+ ///
+ /// If this method not provided or it returns null, header
+ /// will be sticky until offset equals to
+ /// header size
minOffsetProvider: (StickyState state) {},
- /// Header alignment
- ///
- /// Use [HeaderAlignment] to align header to left,
- /// right, top or bottom side
- ///
- /// Optional. Default value [HeaderAlignment.topLeft]
- headerAlignment: HeaderAlignment.topLeft,
+ /// Header alignment against main axis direction
+ ///
+ /// See [HeaderMainAxisAlignment] for more info
+ HeaderMainAxisAlignment mainAxisAlignment: HeaderMainAxisAlignment.start,
+
+ /// Header alignment against cross axis direction
+ ///
+ /// See [HeaderCrossAxisAlignment] for more info
+ HeaderCrossAxisAlignment crossAxisAlignment: HeaderCrossAxisAlignment.start,
+
+ /// Header position against scroll axis for relative positioned headers
+ ///
+ /// Only for relative header positioning
+ HeaderPositionAxis positionAxis: HeaderPositionAxis.mainAxis,
+
+ /// List item padding, see [EdgeInsets] for more info
+ EdgeInsets padding: const EdgeInsets.all(8.0),
/// Scroll direction
///
@@ -257,21 +306,31 @@ InfiniteListItem(
#### Header alignment demo
-
+Relative positioning
+
+
+
+Relative cross axis positioning
+
+
+
+Overlay positioning
+
+
#### Horizontal scroll demo
-
+
### Reverse infinite scroll
Currently package doesn't support `CustomScrollView.reverse` option.
But same result can be achieved with defining `anchor = 1` and
-`maxChildCount = 0`. In that way viewport center will be stick
-to the bottom and positive list won't render anything.
+`posChildCount = 0`. In that way viewport center will be stick to the
+bottom and positive list won't render anything.
-Additionally you can specify `headerAlignment` to any side.
+Additionally you can specify header alignment to any side.
```dart
import 'package:sticky_infinite_list/sticky_infinite_list.dart';
@@ -285,13 +344,14 @@ class Example extends StatelessWidget {
direction: InfiniteListDirection.multi,
- maxChildCount: 0,
+ posChildCount: 0,
builder: (BuildContext context, int index) {
/// Builder requires [InfiniteList] to be returned
return InfiniteListItem(
- headerAlignment: HeaderAlignment.bottomLeft,
+ mainAxisAlignment: HeaderMainAxisAlignment.end,
+ crossAxisAlignment: HeaderCrossAxisAlignment.start,
/// Header builder
headerBuilder: (BuildContext context) {
@@ -314,7 +374,7 @@ class Example extends StatelessWidget {
#### Demo
-
+
For more info take a look at
[Example](https://github.com/TatsuUkraine/flutter_sticky_infinite_list_example) project
@@ -330,14 +390,30 @@ Luckily you can extend and override base `InfiniteListItem` class
```dart
/// Generic `I` is index type, by default list item uses `int`
-class SomeCustomListItem extends InfiniteListItem {
- /// Header alignment
- ///
- /// Supports all sides alignment, see [HeaderAlignment] for more info
- ///
- /// By default [HeaderAlignment.topLeft]
- final HeaderAlignment headerAlignment;
-
+
+class SomeCustomListItem extends InfiniteListItem {
+ /// Header alignment against main axis direction
+ ///
+ /// See [HeaderMainAxisAlignment] for more info
+ @override
+ final HeaderMainAxisAlignment mainAxisAlignment = HeaderMainAxisAlignment.start;
+
+ /// Header alignment against cross axis direction
+ ///
+ /// See [HeaderCrossAxisAlignment] for more info
+ @override
+ final HeaderCrossAxisAlignment crossAxisAlignment = HeaderCrossAxisAlignment.start;
+
+ /// Header position against scroll axis for relative positioned headers
+ ///
+ /// See [HeaderPositionAxis] for more info
+ @override
+ final HeaderPositionAxis positionAxis = HeaderPositionAxis.mainAxis;
+
+ /// If header should overlay content or not
+ @override
+ final bool overlayContent = false;
+
/// Let item builder know if it should watch
/// header position changes
///
@@ -345,7 +421,7 @@ class SomeCustomListItem extends InfiniteListItem {
/// each time header position changes
@override
bool get watchStickyState => true;
-
+
/// Let item builder know that this class
/// provides header
///
@@ -353,7 +429,7 @@ class SomeCustomListItem extends InfiniteListItem {
/// and never called
@override
bool get hasStickyHeader => true;
-
+
/// This methods builds header
///
/// If [watchStickyState] is `true`,
@@ -366,24 +442,24 @@ class SomeCustomListItem extends InfiniteListItem {
/// Also in that case `state` will be `null`
@override
Widget buildHeader(BuildContext context, [StickyState state]) {}
-
+
/// Content item builder
///
/// This method invoked only once
@override
- Widget buildContent(BuildContext context) => {}
+ Widget buildContent(BuildContext context) {}
- /// Called during init state (see Statefull widget [State.initState])
+ /// Called during init state (see [Statefull] widget [State.initState])
///
- /// For additional information about Statefull widget `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])
+ /// Called during item dispose (see [Statefull] widget [State.dispose])
///
- /// For additional information about Statefull widget `dispose`
+ /// For additional information about [Statefull] widget `dispose`
/// lifecycle - see Flutter docs
@protected
@mustCallSuper
@@ -393,11 +469,9 @@ class SomeCustomListItem extends InfiniteListItem {
#### Need more override?..
-**If you get any problems with this type of override,
- please create an issue**
-
Alongside with list item override, to use inside `InfiniteList` builder,
-you can also use `StickyListItem`, that exposed by this package too, independently.
+you can also use or extend `StickyListItem`, that exposed by this
+package too, independently.
This class uses `Stream` to inform it's parent about header position changes
@@ -419,12 +493,24 @@ Widget build(BuildContext context) {
child: Placeholder(),
),
StickyListItem(
+ streamSink: _headerStream.sink, /// stream to update header during scroll
header: Container(
- height: 30,
+ height: _headerHeight,
width: double.infinity,
color: Colors.orange,
child: Center(
- child: Text('Sticky Header')
+ child: StreamBuilder>(
+ stream: _headerStream.stream, /// stream to update header during scroll
+ builder: (_, snapshot) {
+ if (!snapshot.hasData) {
+ return Container();
+ }
+
+ final position = (snapshot.data.position * 100).round();
+
+ return Text('Positioned relative. Position: $position%');
+ },
+ ),
),
),
content: Container(
@@ -432,7 +518,35 @@ Widget build(BuildContext context) {
color: Colors.blueAccent,
child: Placeholder(),
),
- itemIndex: 'single-child-index',
+ itemIndex: "single-child",
+ ),
+ StickyListItem.overlay(
+ streamSink: _headerOverlayStream.sink, /// stream to update header during scroll
+ header: Container(
+ height: _headerHeight,
+ width: double.infinity,
+ color: Colors.orange,
+ child: Center(
+ child: StreamBuilder>(
+ stream: _headerOverlayStream.stream, /// stream to update header during scroll
+ builder: (_, snapshot) {
+ if (!snapshot.hasData) {
+ return Container();
+ }
+
+ final position = (snapshot.data.position * 100).round();
+
+ return Text('Positioned overlay. Position: $position%');
+ },
+ ),
+ ),
+ ),
+ content: Container(
+ height: height,
+ color: Colors.lightBlueAccent,
+ child: Placeholder(),
+ ),
+ itemIndex: "single-overlayed-child",
),
Container(
height: height,
@@ -445,12 +559,12 @@ Widget build(BuildContext context) {
}
```
-This code will render single child scroll
-with 3 widgets. Middle one - item with sticky header.
+This code will render single child scroll with 4 widgets. Two middle
+items - items with sticky header.
**Demo**
-
+
For more complex example please take a look at "Single Example" page
in [Example project](https://github.com/TatsuUkraine/flutter_sticky_infinite_list_example)
diff --git a/example/example.dart b/example/example.dart
index 2850b71..768f61e 100644
--- a/example/example.dart
+++ b/example/example.dart
@@ -19,14 +19,14 @@ class Example extends StatelessWidget {
/// Will be ignored if [direction] is forward
///
/// If it's `null`, list will be infinite
- minChildCount: -100,
+ negChildCount: 100,
/// Render 100 elements in positive direction. `Optional`
///
/// If it's not provided, scroll will be infinite in positive direction
///
/// If it's `null`, list will be infinite
- maxChildCount: 100,
+ posChildCount: 100,
/// ViewPort anchor value. See [ScrollView] docs for more info
anchor: 0.0,
@@ -35,11 +35,6 @@ class Example extends StatelessWidget {
builder: (BuildContext context, int index) {
/// Builder requires [InfiniteList] to be returned
return InfiniteListItem(
- /// If header should be build during initial render.
- ///
- /// Will be ignored with just [headerBuilder] builder specified
- initialHeaderBuild: true,
-
/// Header builder with state
///
/// Will be invoked each time header changes it's position
@@ -92,15 +87,21 @@ class Example extends StatelessWidget {
/// of container
minOffsetProvider: (StickyState state) => 50,
- /// Header alignment
+ /// Header alignment against main axis
///
- /// Currently it supports top left,
- /// top right, bottom left and bottom right alignments
+ /// By default [HeaderMainAxisAlignment.start]
+ mainAxisAlignment: HeaderMainAxisAlignment.start,
+
+ /// Header alignment against main axis
///
- /// By default [HeaderAlignment.topLeft]
- headerAlignment: HeaderAlignment.topLeft,
+ /// By default [HeaderCrossAxisAlignment.start]
+ crossAxisAlignment: HeaderCrossAxisAlignment.start,
+ /// Header alignment placement against scroll axis
+ ///
+ /// By default [HeaderPositionAxis.mainAxis]
+ positionAxis: HeaderPositionAxis.mainAxis,
);
}
);
diff --git a/lib/models/alignments.dart b/lib/models/alignments.dart
new file mode 100644
index 0000000..4c9dd0d
--- /dev/null
+++ b/lib/models/alignments.dart
@@ -0,0 +1,63 @@
+/// Header position axis for content without header overflow
+enum HeaderPositionAxis {
+ /// Align against main axis direction
+ ///
+ /// For vertical scroll column direction will be used, for
+ /// horizontal scroll - row
+ mainAxis,
+
+ /// Align against cross axis direction
+ ///
+ /// For vertical scroll row direction will be used, for
+ /// horizontal scroll - column
+ crossAxis,
+}
+
+/// Main axis direction alignment
+///
+/// For vertical scroll, header will be aligned to the top and bottom edges.
+/// For horizontal scroll header will be aligned to the left and right edges
+///
+/// It also affect side where sticky header will be sticked.
+enum HeaderMainAxisAlignment {
+ /// Start position against main axis
+ ///
+ /// For Horizontal scroll header will be places at the left,
+ /// for vertical - at the top side
+ start,
+
+ /// End alignment
+ ///
+ /// For Horizontal scroll header will be places at the right,
+ /// for vertical - at the bottom side
+ end,
+}
+
+/// Cross axis header alignment
+enum HeaderCrossAxisAlignment {
+ /// Start position against cross axis
+ ///
+ /// For Horizontal scroll header will be places at top,
+ /// for vertical - at the left side
+ start,
+
+ /// Center position against cross axis
+ ///
+ /// This value can be used only with overlay headers,
+ /// or with relative header and [HeaderPositionAxis.mainAxis]
+ center,
+
+ /// End position against cross axis
+ ///
+ /// For Horizontal scroll header will be places at the bottom,
+ /// for vertical - at the right side
+ end,
+}
+
+enum InfiniteListDirection {
+ /// Render only positive infinite list
+ single,
+
+ /// Render both positive and negative infinite lists
+ multi,
+}
\ No newline at end of file
diff --git a/lib/state.dart b/lib/models/sticky_state.dart
similarity index 50%
rename from lib/state.dart
rename to lib/models/sticky_state.dart
index 26adc67..6fdd26a 100644
--- a/lib/state.dart
+++ b/lib/models/sticky_state.dart
@@ -1,47 +1,3 @@
-import 'package:flutter/widgets.dart';
-
-typedef Widget ContentBuilder(BuildContext context);
-typedef Widget HeaderStateBuilder(
- BuildContext context, StickyState state);
-typedef Widget HeaderBuilder(BuildContext context);
-typedef double MinOffsetProvider(StickyState state);
-
-/// List direction variants
-enum InfiniteListDirection {
- /// Render only positive infinite list
- single,
-
- /// Render both positive and negative infinite lists
- multi,
-}
-
-/// Alignment options
-///
-/// [HeaderAlignment.bottomLeft], [HeaderAlignment.bottomRight] and
-/// [HeaderAlignment.bottomCenter] header will be positioned
-/// against content bottom edge for vertical scroll
-///
-/// [HeaderAlignment.topRight], [HeaderAlignment.bottomRight] and
-/// [HeaderAlignment.canterRight] header will be positioned
-/// against content right edge for horizontal scroll
-///
-/// Which also means that headers will become sticky, when content
-/// bottom edge (or right edge for horizontal) will
-/// go outside of ViewPort bottom (right for horizontal) edge
-///
-/// It also affects on [StickyState.offset] value, since in that case
-/// hidden size will be calculated against bottom edges
-enum HeaderAlignment {
- topLeft,
- topCenter,
- topRight,
- bottomLeft,
- bottomCenter,
- bottomRight,
- centerLeft,
- centerRight,
-}
-
/// Sticky state object
/// that describes header position and content height
class StickyState {
@@ -53,13 +9,15 @@ class StickyState {
///
/// `1.0` - max end position
///
- /// If [InfiniteListItem.initialHeaderBuild] is true, initial
- /// header render will be with position = 0
+ /// If [InfiniteListItem.initialHeaderBuild] is true with [InfiniteListItem.overlay],
+ /// or default [InfiniteListItem] constructor is used,
+ /// initial header render will be with position = 0
final double position;
/// Number of pixels, that outside of viewport
///
- /// If [InfiniteListItem.initialHeaderBuild] is true, initial
+ /// If [InfiniteListItem.initialHeaderBuild] is true with [InfiniteListItem.overlay],
+ /// or default [InfiniteListItem] constructor is used,
/// header render will be with offset = 0
///
/// For header bottom positions (or right positions for horizontal)
@@ -83,8 +41,9 @@ class StickyState {
/// Scroll item height.
///
- /// If [InfiniteListItem.initialHeaderBuild] is true, initial
- /// header render will be called without this value
+ /// If [InfiniteListItem.initialHeaderBuild] is true with [InfiniteListItem.overlay],
+ /// or default [InfiniteListItem] constructor is used,
+ /// initial header render will be called without this value
final double contentSize;
StickyState(this.index, {
@@ -107,4 +66,4 @@ class StickyState {
sticky: sticky ?? this.sticky,
contentSize: contentHeight ?? this.contentSize,
);
-}
+}
\ No newline at end of file
diff --git a/lib/models/types.dart b/lib/models/types.dart
new file mode 100644
index 0000000..2690c6b
--- /dev/null
+++ b/lib/models/types.dart
@@ -0,0 +1,8 @@
+import 'package:flutter/widgets.dart';
+
+import 'sticky_state.dart';
+
+typedef Widget ContentBuilder(BuildContext context);
+typedef Widget HeaderStateBuilder(BuildContext context, StickyState state);
+typedef Widget HeaderBuilder(BuildContext context);
+typedef double MinOffsetProvider(StickyState state);
\ No newline at end of file
diff --git a/lib/render.dart b/lib/render.dart
index a639a66..074ab8c 100644
--- a/lib/render.dart
+++ b/lib/render.dart
@@ -3,13 +3,22 @@ import 'dart:math' show max, min;
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
-import './state.dart';
+import 'models/alignments.dart';
+import 'models/sticky_state.dart';
+import 'models/types.dart';
+
+
+/// Sticky item render object based on [RenderStack]
class StickyListItemRenderObject extends RenderStack {
ScrollableState _scrollable;
StreamSink> _streamSink;
I _itemIndex;
MinOffsetProvider _minOffsetProvider;
+ bool _overlayContent;
+ HeaderPositionAxis _positionAxis;
+ HeaderMainAxisAlignment _mainAxisAlignment;
+ HeaderCrossAxisAlignment _crossAxisAlignment;
double _lastOffset;
bool _headerOverflow = false;
@@ -19,18 +28,24 @@ class StickyListItemRenderObject extends RenderStack {
@required I itemIndex,
MinOffsetProvider minOffsetProvider,
StreamSink> streamSink,
- AlignmentGeometry alignment,
TextDirection textDirection,
- StackFit fit,
Overflow overflow,
+ bool overlayContent,
+ HeaderPositionAxis positionAxis = HeaderPositionAxis.mainAxis,
+ HeaderMainAxisAlignment mainAxisAlignment = HeaderMainAxisAlignment.start,
+ HeaderCrossAxisAlignment crossAxisAlignment = HeaderCrossAxisAlignment.start,
}) : _scrollable = scrollable,
_streamSink = streamSink,
_itemIndex = itemIndex,
_minOffsetProvider = minOffsetProvider,
+ _overlayContent = overlayContent,
+ _positionAxis = positionAxis,
+ _mainAxisAlignment = mainAxisAlignment,
+ _crossAxisAlignment = crossAxisAlignment,
super(
- alignment: alignment,
+ alignment: _headerAlignment(scrollable, mainAxisAlignment, crossAxisAlignment),
textDirection: textDirection,
- fit: fit,
+ fit: StackFit.loose,
overflow: overflow,
);
@@ -49,13 +64,39 @@ class StickyListItemRenderObject extends RenderStack {
}
MinOffsetProvider get minOffsetProvider =>
- _minOffsetProvider ?? (state) => 0;
+ _minOffsetProvider ?? (state) => null;
set minOffsetProvider(MinOffsetProvider offsetProvider) {
_minOffsetProvider = offsetProvider;
markNeedsPaint();
}
+ set overlayContent(bool overlayContent) {
+ _overlayContent = overlayContent;
+
+ if (_overlayContent != overlayContent) {
+ markNeedsLayout();
+ }
+ }
+
+ set positionAxis(HeaderPositionAxis positionAxis) {
+ _positionAxis = positionAxis;
+
+ if (_positionAxis != positionAxis) {
+ markNeedsLayout();
+ }
+ }
+
+ set mainAxisAlignment(HeaderMainAxisAlignment axisAlignment) {
+ _mainAxisAlignment = axisAlignment;
+ alignment = _headerAlignment(scrollable, _mainAxisAlignment, _crossAxisAlignment);
+ }
+
+ set crossAxisAlignment(HeaderCrossAxisAlignment axisAlignment) {
+ _crossAxisAlignment = axisAlignment;
+ alignment = _headerAlignment(scrollable, _mainAxisAlignment, _crossAxisAlignment);
+ }
+
ScrollableState get scrollable => _scrollable;
set scrollable(ScrollableState newScrollable) {
@@ -105,16 +146,37 @@ class StickyListItemRenderObject extends RenderStack {
}
}
+ @override
+ void performLayout() {
+ final BoxConstraints constraints = this.constraints;
+ final RenderBox header = _headerBox;
+
+ final BoxConstraints containerConstraints = constraints.loosen();
+
+ header.layout(containerConstraints, parentUsesSize: true);
+
+ size = _layoutContent(containerConstraints, header.size);
+
+ assert(size.width == constraints.constrainWidth(size.width));
+ assert(size.height == constraints.constrainHeight(size.height));
+
+ assert(size.isFinite);
+
+ final StackParentData headerParentData = header.parentData as StackParentData;
+
+ headerParentData.offset = alignment.resolve(TextDirection.ltr).alongOffset(size - header.size as Offset);
+ }
+
void updateHeaderOffset() {
_headerOverflow = false;
final double stuckOffset = _stuckOffset;
final StackParentData parentData = _headerBox.parentData;
- final double contentSize = _getContentDirectionSize();
- final double headerSize = _getHeaderDirectionSize();
+ final double contentSize = _contentDirectionSize;
+ final double headerSize = _headerDirectionSize;
- final double offset = _getStateOffset(stuckOffset, contentSize);
+ final double offset = _calculateStateOffset(stuckOffset, contentSize);
final double position = offset / contentSize;
final StickyState state = StickyState(
@@ -124,14 +186,14 @@ class StickyListItemRenderObject extends RenderStack {
contentSize: contentSize,
);
- final double headerOffset = _getHeaderOffset(
+ final double headerOffset = _calculateHeaderOffset(
contentSize,
stuckOffset,
headerSize,
minOffsetProvider(state)
);
- parentData.offset = _getDirectionalOffset(
+ parentData.offset = _headerDirectionalOffset(
parentData.offset,
headerOffset
);
@@ -145,7 +207,7 @@ class StickyListItemRenderObject extends RenderStack {
sticky: _isSticky(
state,
headerOffset,
- _getHeaderOffset(
+ _calculateHeaderOffset(
contentSize,
stuckOffset,
headerSize
@@ -155,25 +217,62 @@ class StickyListItemRenderObject extends RenderStack {
}
}
- bool get _scrollDirectionVertical =>
- [AxisDirection.up, AxisDirection.down].contains(scrollable.axisDirection);
+ @override
+ double computeMinIntrinsicWidth(double height) {
+ if (
+ _overlayContent ||
+ _scrollDirectionVertical && _positionAxis == HeaderPositionAxis.mainAxis ||
+ !_scrollDirectionVertical && _positionAxis == HeaderPositionAxis.crossAxis
+ ) {
+ return _contentBox.getMinIntrinsicWidth(height);
+ }
- bool get _alignmentStart {
- if (_scrollDirectionVertical) {
- return [
- AlignmentDirectional.topStart,
- AlignmentDirectional.topCenter,
- AlignmentDirectional.topEnd,
- ].contains(alignment);
+ return _contentBox.getMinIntrinsicWidth(height) + _headerBox.getMinIntrinsicWidth(height);
+ }
+
+ @override
+ double computeMaxIntrinsicWidth(double height) {
+ if (
+ _overlayContent ||
+ _scrollDirectionVertical && _positionAxis == HeaderPositionAxis.mainAxis ||
+ !_scrollDirectionVertical && _positionAxis == HeaderPositionAxis.crossAxis
+ ) {
+ return _contentBox.getMaxIntrinsicWidth(height);
+ }
+
+ return _contentBox.getMaxIntrinsicWidth(height) + _headerBox.getMaxIntrinsicWidth(height);
+ }
+
+ @override
+ double computeMinIntrinsicHeight(double width) {
+ if (
+ _overlayContent ||
+ _scrollDirectionVertical && _positionAxis == HeaderPositionAxis.crossAxis ||
+ !_scrollDirectionVertical && _positionAxis == HeaderPositionAxis.mainAxis
+ ) {
+ return _contentBox.getMinIntrinsicHeight(width);
+ }
+
+ return _contentBox.getMinIntrinsicHeight(width) + _headerBox.getMinIntrinsicHeight(width);
+ }
+
+ @override
+ double computeMaxIntrinsicHeight(double width) {
+ if (
+ _overlayContent ||
+ _scrollDirectionVertical && _positionAxis == HeaderPositionAxis.crossAxis ||
+ !_scrollDirectionVertical && _positionAxis == HeaderPositionAxis.mainAxis
+ ) {
+ return _contentBox.getMinIntrinsicHeight(width);
}
- return [
- AlignmentDirectional.topStart,
- AlignmentDirectional.bottomStart,
- AlignmentDirectional.centerStart,
- ].contains(alignment);
+ return _contentBox.getMinIntrinsicHeight(width) + _headerBox.getMinIntrinsicHeight(width);
}
+ bool get _scrollDirectionVertical => _scrollableAxisVertical(scrollable.axisDirection);
+
+ bool get _alignmentStart => _mainAxisAlignment == HeaderMainAxisAlignment.start;
+
double get _scrollableSize {
final viewportContainer = _viewport;
@@ -206,19 +305,15 @@ class StickyListItemRenderObject extends RenderStack {
return _viewport.getOffsetToReveal(this, 0).offset - _scrollable.position.pixels - _scrollableSize;
}
- double _getContentDirectionSize() {
- return _scrollDirectionVertical
- ? _contentBox.size.height
- : _contentBox.size.width;
- }
+ double get _contentDirectionSize => _scrollDirectionVertical
+ ? size.height
+ : size.width;
- double _getHeaderDirectionSize() {
- return _scrollDirectionVertical
- ? _headerBox.size.height
- : _headerBox.size.width;
- }
+ double get _headerDirectionSize => _scrollDirectionVertical
+ ? _headerBox.size.height
+ : _headerBox.size.width;
- Offset _getDirectionalOffset(Offset originalOffset, double offset) {
+ Offset _headerDirectionalOffset(Offset originalOffset, double offset) {
if (_scrollDirectionVertical) {
return Offset(
originalOffset.dx,
@@ -232,8 +327,8 @@ class StickyListItemRenderObject extends RenderStack {
);
}
- double _getStateOffset(double stuckOffset, double contentSize) {
- double offset = _getOffset(stuckOffset, 0, contentSize);
+ double _calculateStateOffset(double stuckOffset, double contentSize) {
+ double offset = _calculateOffset(stuckOffset, 0, contentSize);
if (_alignmentStart) {
return offset;
@@ -242,26 +337,30 @@ class StickyListItemRenderObject extends RenderStack {
return contentSize - offset;
}
- double _getHeaderOffset(
+ double _calculateHeaderOffset(
double contentSize,
double stuckOffset,
double headerSize,
- [double providedMinOffset = 0]
+ [double providedMinOffset]
) {
- final double minOffset = _getMinOffset(contentSize, providedMinOffset);
+ if (providedMinOffset == null) {
+ providedMinOffset = headerSize;
+ }
+
+ final double minOffset = _calculateMinOffset(contentSize, providedMinOffset);
if (_alignmentStart) {
- return _getOffset(stuckOffset, 0, minOffset);
+ return _calculateOffset(stuckOffset, 0, minOffset);
}
- return _getOffset(stuckOffset, minOffset, contentSize) - headerSize;
+ return _calculateOffset(stuckOffset, minOffset, contentSize) - headerSize;
}
- double _getOffset(double current, double minPosition, double maxPosition) {
+ double _calculateOffset(double current, double minPosition, double maxPosition) {
return max(minPosition, min(-current, maxPosition));
}
- double _getMinOffset(double contentSize, double minOffset) {
+ double _calculateMinOffset(double contentSize, double minOffset) {
if (_alignmentStart) {
return contentSize - minOffset;
}
@@ -284,4 +383,117 @@ class StickyListItemRenderObject extends RenderStack {
state.position < 1
);
}
+
+ Size _layoutContent(BoxConstraints constraints, Size headerSize) {
+ final RenderBox content = _contentBox;
+ final StackParentData contentParentData = content.parentData as StackParentData;
+ contentParentData.offset = Offset.zero;
+
+ if (!_overlayContent) {
+ if (
+ (
+ _positionAxis == HeaderPositionAxis.crossAxis &&
+ _scrollDirectionVertical
+ ) ||
+ (
+ _positionAxis == HeaderPositionAxis.mainAxis &&
+ !_scrollDirectionVertical
+ )
+ ) {
+ content.layout(constraints.copyWith(
+ maxWidth: constraints.maxWidth - headerSize.width
+ ), parentUsesSize: true);
+
+ if (
+ (
+ _crossAxisAlignment == HeaderCrossAxisAlignment.start &&
+ _scrollDirectionVertical
+ ) ||
+ (
+ _mainAxisAlignment == HeaderMainAxisAlignment.start &&
+ !_scrollDirectionVertical
+ )
+ ) {
+ contentParentData.offset = Offset(headerSize.width, 0);
+ }
+
+ final Size contentSize = content.size;
+
+ return Size(
+ contentSize.width + headerSize.width,
+ contentSize.height
+ );
+ }
+
+ if (
+ (
+ _positionAxis == HeaderPositionAxis.mainAxis &&
+ _scrollDirectionVertical
+ ) ||
+ (
+ _positionAxis == HeaderPositionAxis.crossAxis &&
+ !_scrollDirectionVertical
+ )
+ ) {
+ content.layout(constraints.copyWith(
+ maxHeight: constraints.maxHeight - headerSize.height
+ ), parentUsesSize: true);
+
+ if (
+ (
+ _mainAxisAlignment == HeaderMainAxisAlignment.start &&
+ _scrollDirectionVertical
+ ) ||
+ (
+ _crossAxisAlignment == HeaderCrossAxisAlignment.start &&
+ !_scrollDirectionVertical
+ )
+ ) {
+ contentParentData.offset = Offset(0, headerSize.height);
+ }
+
+ final Size contentSize = content.size;
+
+ return Size(
+ contentSize.width,
+ contentSize.height + headerSize.height
+ );
+ }
+ }
+
+ content.layout(constraints, parentUsesSize: true);
+
+ return content.size;
+ }
+
+ static AlignmentGeometry _headerAlignment(ScrollableState scrollable, HeaderMainAxisAlignment mainAxisAlignment, HeaderCrossAxisAlignment crossAxisAlignment) {
+ final bool vertical = _scrollableAxisVertical(scrollable.axisDirection);
+
+ switch (crossAxisAlignment) {
+
+ case HeaderCrossAxisAlignment.end:
+ if (mainAxisAlignment == HeaderMainAxisAlignment.end) {
+ return Alignment.bottomRight;
+ }
+
+ return vertical ? Alignment.topRight : Alignment.bottomLeft;
+
+ case HeaderCrossAxisAlignment.center:
+ if (mainAxisAlignment == HeaderMainAxisAlignment.start) {
+ return vertical ? Alignment.topCenter : Alignment.centerLeft;
+ }
+
+ return vertical ? Alignment.bottomCenter : Alignment.centerRight;
+
+ case HeaderCrossAxisAlignment.start:
+ default:
+ if (mainAxisAlignment == HeaderMainAxisAlignment.start) {
+ return Alignment.topLeft;
+ }
+
+ return vertical ? Alignment.bottomLeft : Alignment.topRight;
+ }
+ }
+
+ static bool _scrollableAxisVertical(AxisDirection direction) => [AxisDirection.up, AxisDirection.down].contains(direction);
}
diff --git a/lib/sticky_infinite_list.dart b/lib/sticky_infinite_list.dart
index 9b0df2a..76685b6 100644
--- a/lib/sticky_infinite_list.dart
+++ b/lib/sticky_infinite_list.dart
@@ -2,4 +2,6 @@ library sticky_infinite_list;
export './widget.dart';
export './render.dart';
-export './state.dart';
+export './models/alignments.dart';
+export './models/sticky_state.dart';
+export './models/types.dart';
diff --git a/lib/widget.dart b/lib/widget.dart
index db025de..259aa7d 100644
--- a/lib/widget.dart
+++ b/lib/widget.dart
@@ -2,8 +2,11 @@ import 'dart:async';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
-import './state.dart';
+
import './render.dart';
+import 'models/sticky_state.dart';
+import 'models/types.dart';
+import 'models/alignments.dart';
typedef InfiniteListItem ItemBuilder(BuildContext context, I index);
@@ -13,16 +16,14 @@ typedef InfiniteListItem ItemBuilder(BuildContext context, I index);
///
/// This class build item header and content
class InfiniteListItem {
+ /// Header builder based on [StickyState]
final HeaderStateBuilder headerStateBuilder;
+
+ /// Header builder
final HeaderBuilder headerBuilder;
- final ContentBuilder contentBuilder;
- /// Header alignment
- ///
- /// By default [HeaderAlignment.topLeft]
- ///
- /// For more option take a look in [HeaderAlignment]
- final HeaderAlignment headerAlignment;
+ /// Content builder
+ final ContentBuilder contentBuilder;
/// Function, that provides min offset.
///
@@ -53,20 +54,71 @@ class InfiniteListItem {
///
/// For case when only [headerBuilder] is defined,
/// this property will be ignored
+ ///
+ /// If it's relative header positioning ([InfiniteListItem.overlay] constructor is used),
+ /// this property always will be `true`, which means that with relative
+ /// positioning, header will be built with basic [StickyState] object.
+ ///
+ /// It's required due to layout container and define it's actual dimensions
final bool initialHeaderBuild;
- InfiniteListItem({
+ /// Header alignment against main axis direction.
+ ///
+ /// Affects header stick side.
+ ///
+ /// See [HeaderMainAxisAlignment] for more info
+ final HeaderMainAxisAlignment mainAxisAlignment;
+
+ /// Header alignment against cross axis direction
+ ///
+ /// See [HeaderCrossAxisAlignment] for more info
+ final HeaderCrossAxisAlignment crossAxisAlignment;
+
+ /// Header position against scroll axis for relative positioned headers
+ ///
+ /// See [HeaderPositionAxis] for more info
+ final HeaderPositionAxis positionAxis;
+
+ /// List item padding, see [EdgeInsets] for more info
+ final EdgeInsets padding;
+
+ /// If header should overlay content or not
+ final bool overlayContent;
+
+ /// Default list item constructor with relative header positioning
+ const InfiniteListItem({
+ @required this.contentBuilder,
+ this.headerBuilder,
+ this.headerStateBuilder,
+ this.minOffsetProvider,
+ this.mainAxisAlignment = HeaderMainAxisAlignment.start,
+ this.crossAxisAlignment = HeaderCrossAxisAlignment.start,
+ this.positionAxis = HeaderPositionAxis.mainAxis,
+ this.padding,
+ }): overlayContent = false,
+ initialHeaderBuild = true;
+
+ /// List item constructor with overlayed header positioning
+ const InfiniteListItem.overlay({
@required this.contentBuilder,
this.headerBuilder,
this.headerStateBuilder,
this.minOffsetProvider,
- this.headerAlignment = HeaderAlignment.topLeft,
this.initialHeaderBuild = false,
- });
-
+ this.mainAxisAlignment = HeaderMainAxisAlignment.start,
+ this.crossAxisAlignment = HeaderCrossAxisAlignment.start,
+ this.padding,
+ })
+ : positionAxis = HeaderPositionAxis.mainAxis,
+ overlayContent = true;
+
+ /// Defines if list item has Header
bool get hasStickyHeader =>
headerBuilder != null || headerStateBuilder != null;
+ /// Defines if list item should watch header position state changes.
+ ///
+ /// It's true if [headerStateBuilder] was provided instead of [headerBuilder]
bool get watchStickyState => headerStateBuilder != null;
/// Header item builder
@@ -97,25 +149,23 @@ class InfiniteListItem {
@mustCallSuper
void dispose() {}
- Widget _getHeader(BuildContext context, Stream> stream, I index) {
+ Widget _buildHeader(BuildContext context, Stream> stream, I index) {
assert(hasStickyHeader, "At least one builder should be provided");
if (!watchStickyState) {
return buildHeader(context);
}
- return Positioned(
- child: StreamBuilder>(
- stream: stream,
- initialData: initialHeaderBuild ? StickyState(index) : null,
- builder: (context, snapshot) {
- if (!snapshot.hasData) {
- return Container();
- }
-
- return buildHeader(context, snapshot.data);
- },
- ),
+ return StreamBuilder>(
+ stream: stream,
+ initialData: initialHeaderBuild ? StickyState(index) : null,
+ builder: (context, snapshot) {
+ if (!snapshot.hasData) {
+ return Container();
+ }
+
+ return buildHeader(context, snapshot.data);
+ },
);
}
}
@@ -146,15 +196,12 @@ class InfiniteList extends StatefulWidget {
final InfiniteListDirection direction;
/// Max child count for positive direction list
- final int maxChildCount;
+ final int posChildCount;
/// Max child count for negative list direction
///
/// Ignored when [direction] is [InfiniteListDirection.single]
- ///
- /// This value should have negative value in order to provide right calculation
- /// for negative list
- final int minChildCount;
+ final int negChildCount;
/// Proxy property for [ScrollView.reverse]
///
@@ -188,8 +235,8 @@ class InfiniteList extends StatefulWidget {
@required this.builder,
this.controller,
this.direction = InfiniteListDirection.single,
- this.maxChildCount,
- this.minChildCount,
+ this.posChildCount,
+ this.negChildCount,
//this.reverse = false,
this.anchor = 0.0,
this.cacheExtent,
@@ -206,28 +253,25 @@ class _InfiniteListState extends State {
StreamController _streamController =
StreamController>.broadcast();
- int get _reverseChildCount =>
- widget.minChildCount == null ? null : widget.minChildCount * -1;
-
SliverList get _reverseList =>
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) =>
- _getListItem(context, (index + 1) * -1),
- childCount: _reverseChildCount,
+ _buildListItem(context, (index + 1) * -1),
+ childCount: widget.negChildCount,
),
);
SliverList get _forwardList =>
SliverList(
delegate: SliverChildBuilderDelegate(
- _getListItem,
- childCount: widget.maxChildCount,
+ _buildListItem,
+ childCount: widget.posChildCount,
),
key: widget._centerKey,
);
- Widget _getListItem(BuildContext context, int index) =>
+ Widget _buildListItem(BuildContext context, int index) =>
_StickySliverListItem(
streamController: _streamController,
index: index,
@@ -287,39 +331,7 @@ class _StickySliverListItem extends StatefulWidget {
}) : super(key: key);
@override
- State<_StickySliverListItem> createState() =>
- _StickySliverListItemState();
-
- /// Maps sticky header alignment values
- /// to [AlignmentDirectional] variant
- AlignmentDirectional get alignment {
- switch (listItem.headerAlignment) {
- case HeaderAlignment.centerLeft:
- return AlignmentDirectional.centerStart;
-
- case HeaderAlignment.centerRight:
- return AlignmentDirectional.centerEnd;
-
- case HeaderAlignment.bottomLeft:
- return AlignmentDirectional.bottomStart;
-
- case HeaderAlignment.bottomCenter:
- return AlignmentDirectional.bottomCenter;
-
- case HeaderAlignment.bottomRight:
- return AlignmentDirectional.bottomEnd;
-
- case HeaderAlignment.bottomCenter:
- return AlignmentDirectional.bottomCenter;
-
- case HeaderAlignment.topRight:
- return AlignmentDirectional.topEnd;
-
- case HeaderAlignment.topLeft:
- default:
- return AlignmentDirectional.topStart;
- }
- }
+ State<_StickySliverListItem> createState() => _StickySliverListItemState();
}
class _StickySliverListItemState extends State<_StickySliverListItem> {
@@ -331,33 +343,63 @@ class _StickySliverListItemState extends State<_StickySliverListItem> {
}
@override
+
Widget build(BuildContext context) {
+ if (widget.listItem.padding == null) {
+ return _buildItem(context);
+ }
+
+ return Padding(
+ padding: widget.listItem.padding,
+ child: _buildItem(context),
+ );
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+
+ widget.listItem.dispose();
+ }
+
+ Widget _buildItem(BuildContext context) {
final Widget content = widget.listItem.buildContent(context);
if (!widget.listItem.hasStickyHeader) {
return content;
}
+ if (widget.listItem.overlayContent) {
+ return StickyListItem.overlay(
+ itemIndex: widget.index,
+ streamSink: widget.streamController.sink,
+ header: widget.listItem._buildHeader(
+ context,
+ widget._stream,
+ widget.index
+ ),
+ content: content,
+ minOffsetProvider: widget.listItem.minOffsetProvider,
+ mainAxisAlignment: widget.listItem.mainAxisAlignment,
+ crossAxisAlignment: widget.listItem.crossAxisAlignment,
+ );
+ }
+
return StickyListItem(
itemIndex: widget.index,
streamSink: widget.streamController.sink,
- header: widget.listItem._getHeader(
+ header: widget.listItem._buildHeader(
context,
widget._stream,
widget.index
),
content: content,
minOffsetProvider: widget.listItem.minOffsetProvider,
- alignment: widget.alignment,
+ mainAxisAlignment: widget.listItem.mainAxisAlignment,
+ crossAxisAlignment: widget.listItem.crossAxisAlignment,
+ positionAxis: widget.listItem.positionAxis,
);
}
-
- @override
- void dispose() {
- super.dispose();
-
- widget.listItem.dispose();
- }
}
/// Sticky list item that provides header offset calculation
@@ -375,21 +417,72 @@ class StickyListItem extends Stack {
/// during stream event emit
final I itemIndex;
- /// Callback function that tells when header to stick to the bottom
+ /// Callback function that tells when header to stick to the bottom.
+ ///
+ /// If it returns `null` or callback not provided - min offset will be header height
final MinOffsetProvider minOffsetProvider;
+ /// Header alignment against main axis direction
+ ///
+ /// Affects header stick side.
+ ///
+ /// See [HeaderMainAxisAlignment] for more info
+ final HeaderMainAxisAlignment mainAxisAlignment;
+
+ /// Header alignment against cross axis direction
+ ///
+ /// See [HeaderCrossAxisAlignment] for more info
+ final HeaderCrossAxisAlignment crossAxisAlignment;
+
+ /// Header position against scroll axis for relative positioned headers
+ ///
+ /// See [HeaderPositionAxis] for more info
+ final HeaderPositionAxis positionAxis;
+
+ /// Defines if header should overlay content
+ final bool overlayContent;
+
+ /// Default sticky item constructor with relative header positioning
StickyListItem({
@required Widget header,
@required Widget content,
@required this.itemIndex,
this.minOffsetProvider,
this.streamSink,
- AlignmentDirectional alignment,
+ this.mainAxisAlignment = HeaderMainAxisAlignment.start,
+ this.crossAxisAlignment = HeaderCrossAxisAlignment.start,
+ this.positionAxis = HeaderPositionAxis.mainAxis,
+ Key key,
+ })
+ : overlayContent = false,
+ assert(
+ positionAxis == HeaderPositionAxis.mainAxis || crossAxisAlignment != HeaderCrossAxisAlignment.center,
+ 'Center cross axis alignment can\'t be used with Cross axis positioning'
+ ),
+ super(
+ key: key,
+ children: [content, header],
+ overflow: Overflow.clip,
+ );
+
+ /// Default sticky item constructor with overlayed header positioning.
+ ///
+ /// Header position axis in this case will be against main axis always.
+ StickyListItem.overlay({
+ @required Widget header,
+ @required Widget content,
+ @required this.itemIndex,
+ this.minOffsetProvider,
+ this.streamSink,
+ this.mainAxisAlignment = HeaderMainAxisAlignment.start,
+ this.crossAxisAlignment = HeaderCrossAxisAlignment.start,
Key key,
- }) : super(
+ })
+ : overlayContent = true,
+ positionAxis = HeaderPositionAxis.mainAxis,
+ super(
key: key,
children: [content, header],
- alignment: alignment ?? AlignmentDirectional.topStart,
overflow: Overflow.clip,
);
@@ -400,9 +493,11 @@ class StickyListItem extends Stack {
RenderStack createRenderObject(BuildContext context) =>
StickyListItemRenderObject(
scrollable: _getScrollableState(context),
- alignment: alignment,
+ mainAxisAlignment: mainAxisAlignment,
+ crossAxisAlignment: crossAxisAlignment,
+ positionAxis: positionAxis,
textDirection: textDirection ?? Directionality.of(context),
- fit: fit,
+ overlayContent: overlayContent,
overflow: overflow,
itemIndex: itemIndex,
streamSink: streamSink,
@@ -419,7 +514,11 @@ class StickyListItem extends Stack {
..scrollable = _getScrollableState(context)
..itemIndex = itemIndex
..streamSink = streamSink
- ..minOffsetProvider = minOffsetProvider;
+ ..minOffsetProvider = minOffsetProvider
+ ..mainAxisAlignment = mainAxisAlignment
+ ..crossAxisAlignment = crossAxisAlignment
+ ..positionAxis = positionAxis
+ ..overlayContent = overlayContent;
}
}
}
diff --git a/pubspec.lock b/pubspec.lock
index aebdafa..97283e8 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1,34 +1,62 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
+ archive:
+ dependency: transitive
+ description:
+ name: archive
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.13"
+ args:
+ dependency: transitive
+ description:
+ name: args
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.6.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
- version: "2.3.0"
+ version: "2.4.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
- version: "1.0.5"
+ version: "2.0.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.2"
+ version: "1.1.3"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
- version: "1.14.11"
+ version: "1.14.12"
+ convert:
+ dependency: transitive
+ description:
+ name: convert
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.1"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.4"
flutter:
dependency: "direct main"
description: flutter
@@ -39,20 +67,27 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ image:
+ dependency: transitive
+ description:
+ name: image
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.12"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
- version: "0.12.5"
+ version: "0.12.6"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.7"
+ version: "1.1.8"
path:
dependency: transitive
description:
@@ -60,20 +95,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.4"
- pedantic:
+ petitparser:
dependency: transitive
description:
- name: pedantic
+ name: petitparser
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.0+1"
+ version: "2.4.0"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.5"
+ version: "2.1.3"
sky_engine:
dependency: transitive
description: flutter
@@ -85,7 +120,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
- version: "1.5.5"
+ version: "1.7.0"
stack_trace:
dependency: transitive
description:
@@ -120,7 +155,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
- version: "0.2.5"
+ version: "0.2.15"
typed_data:
dependency: transitive
description:
@@ -135,5 +170,12 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
+ xml:
+ dependency: transitive
+ description:
+ name: xml
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.6.1"
sdks:
- dart: ">=2.2.2 <3.0.0"
+ dart: ">=2.6.0 <3.0.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 0194eb1..1085c22 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -5,8 +5,7 @@ description: >-
Can be customized or with config options or with override.
-version: 1.3.0
-author: TatsuUkraine
+version: 2.0.0
homepage: https://github.com/TatsuUkraine/flutter_sticky_infinite_list
repository: https://github.com/TatsuUkraine/flutter_sticky_infinite_list
issue_tracker: https://github.com/TatsuUkraine/flutter_sticky_infinite_list/issues