Created
August 25, 2019 12:24
-
-
Save orestesgaolin/31917e8c6626baaa924bebe96fd6fd45 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
import 'dart:math' as math; | |
class SliverGridPage extends StatefulWidget { | |
@override | |
_SliverGridPageState createState() => _SliverGridPageState(); | |
} | |
class _SliverGridPageState extends State<SliverGridPage> { | |
ScrollController controller; | |
@override | |
void initState() { | |
super.initState(); | |
controller = ScrollController(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: CustomScrollView( | |
controller: controller, | |
slivers: <Widget>[ | |
Test(controller: controller), | |
], | |
), | |
); | |
} | |
} | |
class Test extends StatelessWidget { | |
const Test({ | |
Key key, | |
@required this.controller, | |
}) : super(key: key); | |
final ScrollController controller; | |
@override | |
Widget build(BuildContext context) { | |
return SliverAnimatedGrid( | |
gridDelegate: SliverGridDelegateWithFixedCrossAxisCountAndAnimation( | |
crossAxisCount: 2, | |
childAspectRatio: 1, | |
mainAxisSpacing: controller.offset, | |
controller: controller, | |
), | |
delegate: SliverChildBuilderDelegate( | |
(BuildContext context, int index) { | |
return Container( | |
alignment: Alignment.center, | |
color: Colors.teal[100 * (index % 9) + 100], | |
child: Text( | |
'$index ', | |
style: TextStyle( | |
fontSize: 40, | |
color: Colors.white, | |
fontWeight: FontWeight.bold), | |
), | |
); | |
}, | |
childCount: 100, | |
), | |
); | |
} | |
} | |
class SliverAnimatedGrid extends SliverMultiBoxAdaptorWidget { | |
const SliverAnimatedGrid({ | |
Key key, | |
@required SliverChildDelegate delegate, | |
@required this.gridDelegate, | |
}) : super(key: key, delegate: delegate); | |
SliverAnimatedGrid.count({ | |
Key key, | |
@required int crossAxisCount, | |
double mainAxisSpacing = 0.0, | |
double crossAxisSpacing = 0.0, | |
double childAspectRatio = 1.0, | |
List<Widget> children = const <Widget>[], | |
}) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount( | |
crossAxisCount: crossAxisCount, | |
mainAxisSpacing: mainAxisSpacing, | |
crossAxisSpacing: crossAxisSpacing, | |
childAspectRatio: childAspectRatio, | |
), | |
super(key: key, delegate: SliverChildListDelegate(children)); | |
SliverAnimatedGrid.extent({ | |
Key key, | |
@required double maxCrossAxisExtent, | |
double mainAxisSpacing = 0.0, | |
double crossAxisSpacing = 0.0, | |
double childAspectRatio = 1.0, | |
List<Widget> children = const <Widget>[], | |
}) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent( | |
maxCrossAxisExtent: maxCrossAxisExtent, | |
mainAxisSpacing: mainAxisSpacing, | |
crossAxisSpacing: crossAxisSpacing, | |
childAspectRatio: childAspectRatio, | |
), | |
super(key: key, delegate: SliverChildListDelegate(children)); | |
final SliverGridDelegate gridDelegate; | |
@override | |
RenderSliverGrid createRenderObject(BuildContext context) { | |
final SliverMultiBoxAdaptorElement element = context; | |
return RenderSliverGrid(childManager: element, gridDelegate: gridDelegate); | |
} | |
@override | |
void updateRenderObject(BuildContext context, RenderSliverGrid renderObject) { | |
renderObject.gridDelegate = gridDelegate; | |
} | |
@override | |
double estimateMaxScrollOffset( | |
SliverConstraints constraints, | |
int firstIndex, | |
int lastIndex, | |
double leadingScrollOffset, | |
double trailingScrollOffset, | |
) { | |
return super.estimateMaxScrollOffset( | |
constraints, | |
firstIndex, | |
lastIndex, | |
leadingScrollOffset, | |
trailingScrollOffset, | |
) ?? | |
gridDelegate | |
.getLayout(constraints) | |
.computeMaxScrollOffset(delegate.estimatedChildCount); | |
} | |
} | |
class SliverGridRegularTileLayout extends SliverGridLayout { | |
const SliverGridRegularTileLayout({ | |
@required this.crossAxisCount, | |
@required this.mainAxisStride, | |
@required this.crossAxisStride, | |
@required this.childMainAxisExtent, | |
@required this.childCrossAxisExtent, | |
@required this.reverseCrossAxis, | |
}) : assert(crossAxisCount != null && crossAxisCount > 0), | |
assert(mainAxisStride != null && mainAxisStride >= 0), | |
assert(crossAxisStride != null && crossAxisStride >= 0), | |
assert(childMainAxisExtent != null && childMainAxisExtent >= 0), | |
assert(childCrossAxisExtent != null && childCrossAxisExtent >= 0), | |
assert(reverseCrossAxis != null); | |
final int crossAxisCount; | |
final double mainAxisStride; | |
final double crossAxisStride; | |
final double childMainAxisExtent; | |
final double childCrossAxisExtent; | |
final bool reverseCrossAxis; | |
@override | |
int getMinChildIndexForScrollOffset(double scrollOffset) { | |
return mainAxisStride > 0.0 | |
? crossAxisCount * (scrollOffset ~/ mainAxisStride) | |
: 0; | |
} | |
@override | |
int getMaxChildIndexForScrollOffset(double scrollOffset) { | |
if (mainAxisStride > 0.0) { | |
final int mainAxisCount = (scrollOffset / mainAxisStride).ceil(); | |
return math.max(0, crossAxisCount * mainAxisCount - 1); | |
} | |
return 0; | |
} | |
double _getOffsetFromStartInCrossAxis(double crossAxisStart) { | |
if (reverseCrossAxis) | |
return crossAxisCount * crossAxisStride - | |
crossAxisStart - | |
childCrossAxisExtent - | |
(crossAxisStride - childCrossAxisExtent); | |
return crossAxisStart; | |
} | |
@override | |
SliverGridGeometry getGeometryForChildIndex(int index) { | |
final double crossAxisStart = (index % crossAxisCount) * crossAxisStride; | |
return SliverGridGeometry( | |
scrollOffset: (index ~/ crossAxisCount) * mainAxisStride, | |
crossAxisOffset: _getOffsetFromStartInCrossAxis(crossAxisStart), | |
mainAxisExtent: childMainAxisExtent, | |
crossAxisExtent: childCrossAxisExtent, | |
); | |
} | |
@override | |
double computeMaxScrollOffset(int childCount) { | |
assert(childCount != null); | |
final int mainAxisCount = ((childCount - 1) ~/ crossAxisCount) + 1; | |
final double mainAxisSpacing = mainAxisStride - childMainAxisExtent; | |
return mainAxisStride * mainAxisCount - mainAxisSpacing; | |
} | |
} | |
class SliverGridDelegateWithFixedCrossAxisCountAndAnimation | |
extends SliverGridDelegate { | |
const SliverGridDelegateWithFixedCrossAxisCountAndAnimation({ | |
@required this.crossAxisCount, | |
this.mainAxisSpacing = 0.0, | |
this.crossAxisSpacing = 0.0, | |
this.childAspectRatio = 1.0, | |
this.controller, | |
}) : assert(crossAxisCount != null && crossAxisCount > 0), | |
assert(mainAxisSpacing != null && mainAxisSpacing >= 0), | |
assert(crossAxisSpacing != null && crossAxisSpacing >= 0), | |
assert(childAspectRatio != null && childAspectRatio > 0); | |
/// Added scroll controller to have access to current position (velocity maybe?) | |
final ScrollController controller; | |
final int crossAxisCount; | |
final double mainAxisSpacing; | |
final double crossAxisSpacing; | |
final double childAspectRatio; | |
bool _debugAssertIsValid() { | |
assert(crossAxisCount > 0); | |
assert(mainAxisSpacing >= 0.0); | |
assert(crossAxisSpacing >= 0.0); | |
assert(childAspectRatio > 0.0); | |
return true; | |
} | |
@override | |
SliverGridLayout getLayout(SliverConstraints constraints) { | |
assert(_debugAssertIsValid()); | |
final double usableCrossAxisExtent = | |
constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1); | |
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount; | |
final double childMainAxisExtent = childCrossAxisExtent / childAspectRatio; | |
// Here accessing scroll controller velocity | |
final velocity = (controller.position.activity.velocity / 100.0).clamp(0, 20); | |
return SliverGridRegularTileLayout( | |
crossAxisCount: crossAxisCount, | |
mainAxisStride: childMainAxisExtent + mainAxisSpacing + velocity, | |
crossAxisStride: childCrossAxisExtent + crossAxisSpacing, | |
childMainAxisExtent: childMainAxisExtent, | |
childCrossAxisExtent: childCrossAxisExtent, | |
reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), | |
); | |
} | |
@override | |
bool shouldRelayout( | |
SliverGridDelegateWithFixedCrossAxisCountAndAnimation oldDelegate) { | |
return oldDelegate.crossAxisCount != crossAxisCount || | |
oldDelegate.mainAxisSpacing != mainAxisSpacing || | |
oldDelegate.crossAxisSpacing != crossAxisSpacing || | |
oldDelegate.childAspectRatio != childAspectRatio; | |
} | |
} |
excuse me. Did you solve it? How to animate items in list while scrolling in Flutter
unfortunately not
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
excuse me. Did you solve it? How to animate items in list while scrolling in Flutter