Skip to content

Instantly share code, notes, and snippets.

@boyan01
Created June 25, 2019 05:55
Show Gist options
  • Save boyan01/29f648340193e6b556f86ef05369627b to your computer and use it in GitHub Desktop.
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
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