Created
June 25, 2019 05:55
-
-
Save boyan01/29f648340193e6b556f86ef05369627b to your computer and use it in GitHub Desktop.
reoder flutter grid list item paint sequence , make current focused index paint in the front
This file contains hidden or 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'; | |
class FocusGridView extends GridView { | |
FocusGridView.builder({ | |
Key key, | |
Axis scrollDirection = Axis.vertical, | |
bool reverse = false, | |
ScrollController controller, | |
bool primary, | |
ScrollPhysics physics, | |
bool shrinkWrap = false, | |
EdgeInsetsGeometry padding, | |
SliverGridDelegate gridDelegate, | |
@required IndexedWidgetBuilder itemBuilder, | |
int itemCount, | |
bool addAutomaticKeepAlives = true, | |
bool addRepaintBoundaries = true, | |
bool addSemanticIndexes = true, | |
double cacheExtent, | |
int semanticChildCount, | |
}) : assert(gridDelegate != null), | |
super.builder( | |
key: key, | |
scrollDirection: scrollDirection, | |
reverse: reverse, | |
controller: controller, | |
primary: primary, | |
physics: physics, | |
shrinkWrap: shrinkWrap, | |
gridDelegate: gridDelegate, | |
itemBuilder: itemBuilder, | |
itemCount: itemCount, | |
padding: padding, | |
cacheExtent: cacheExtent, | |
addAutomaticKeepAlives: addAutomaticKeepAlives, | |
addRepaintBoundaries: addAutomaticKeepAlives, | |
addSemanticIndexes: addSemanticIndexes, | |
semanticChildCount: semanticChildCount ?? itemCount, | |
); | |
@override | |
Widget buildChildLayout(BuildContext context) { | |
return FocusSliverGrid(delegate: childrenDelegate, gridDelegate: gridDelegate); | |
} | |
} | |
class FocusSliverGrid extends SliverGrid { | |
const FocusSliverGrid({ | |
Key key, | |
@required SliverChildDelegate delegate, | |
@required SliverGridDelegate gridDelegate, | |
}) : super(key: key, gridDelegate: gridDelegate, delegate: delegate); | |
@override | |
RenderSliverGrid createRenderObject(BuildContext context) { | |
debugPrint("createRenderObject"); | |
final SliverMultiBoxAdaptorElement element = context; | |
return FocusRenderSliverGrid( | |
childManager: element, gridDelegate: gridDelegate); | |
} | |
@override | |
SliverMultiBoxAdaptorElement createElement() { | |
return super.createElement(); | |
} | |
@override | |
void updateRenderObject( | |
BuildContext context, FocusRenderSliverGrid renderObject) { | |
super.updateRenderObject(context, renderObject); | |
} | |
} | |
class FocusRenderSliverGrid extends RenderSliverGrid { | |
int _focusedIndex = -1; | |
set focusedIndex(int focusIndex) { | |
_focusedIndex = focusIndex; | |
markNeedsPaint(); | |
} | |
FocusRenderSliverGrid({ | |
@required RenderSliverBoxChildManager childManager, | |
@required SliverGridDelegate gridDelegate, | |
}) : super(childManager: childManager, gridDelegate: gridDelegate); | |
@override | |
void paint(PaintingContext context, Offset offset) { | |
if (firstChild == null) return; | |
// offset is to the top-left corner, regardless of our axis direction. | |
// originOffset gives us the delta from the real origin to the origin in the axis direction. | |
Offset mainAxisUnit, crossAxisUnit, originOffset; | |
bool addExtent; | |
switch (applyGrowthDirectionToAxisDirection( | |
constraints.axisDirection, constraints.growthDirection)) { | |
case AxisDirection.up: | |
mainAxisUnit = const Offset(0.0, -1.0); | |
crossAxisUnit = const Offset(1.0, 0.0); | |
originOffset = offset + Offset(0.0, geometry.paintExtent); | |
addExtent = true; | |
break; | |
case AxisDirection.right: | |
mainAxisUnit = const Offset(1.0, 0.0); | |
crossAxisUnit = const Offset(0.0, 1.0); | |
originOffset = offset; | |
addExtent = false; | |
break; | |
case AxisDirection.down: | |
mainAxisUnit = const Offset(0.0, 1.0); | |
crossAxisUnit = const Offset(1.0, 0.0); | |
originOffset = offset; | |
addExtent = false; | |
break; | |
case AxisDirection.left: | |
mainAxisUnit = const Offset(-1.0, 0.0); | |
crossAxisUnit = const Offset(0.0, 1.0); | |
originOffset = offset + Offset(geometry.paintExtent, 0.0); | |
addExtent = true; | |
break; | |
} | |
assert(mainAxisUnit != null); | |
assert(addExtent != null); | |
void paintChild(RenderBox child) { | |
final double mainAxisDelta = childMainAxisPosition(child); | |
final double crossAxisDelta = childCrossAxisPosition(child); | |
Offset childOffset = Offset( | |
originOffset.dx + | |
mainAxisUnit.dx * mainAxisDelta + | |
crossAxisUnit.dx * crossAxisDelta, | |
originOffset.dy + | |
mainAxisUnit.dy * mainAxisDelta + | |
crossAxisUnit.dy * crossAxisDelta, | |
); | |
if (addExtent) childOffset += mainAxisUnit * paintExtentOf(child); | |
// If the child's visible interval (mainAxisDelta, mainAxisDelta + paintExtentOf(child)) | |
// does not intersect the paint extent interval (0, constraints.remainingPaintExtent), it's hidden. | |
if (mainAxisDelta < constraints.remainingPaintExtent && | |
mainAxisDelta + paintExtentOf(child) > 0) | |
context.paintChild(child, childOffset); | |
} | |
RenderBox child = firstChild; | |
RenderBox focused; | |
while (child != null) { | |
if (_focusedIndex != -1 && | |
focused == null && | |
indexOf(child) == _focusedIndex) { | |
focused = child; | |
child = childAfter(child); | |
continue; | |
} | |
paintChild(child); | |
child = childAfter(child); | |
} | |
//paint focused child last, ensure it paint on top | |
if (focused != null) paintChild(focused); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment