-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Closed
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listf: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.waiting for PR to land (fixed)A fix is in flightA fix is in flight
Description
While writing tests for ensureVisible in 2D, found a bug in how the 2D viewport calculates the paint offset of the children when reversed.
Expected:
Actual:
import 'dart:math' as math;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(const SimpleTest());
}
class SimpleTest extends StatelessWidget {
const SimpleTest({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SimpleTableView(
mainAxis: Axis.vertical,
primary: true,
verticalDetails: const ScrollableDetails.vertical(reverse: true),
horizontalDetails: const ScrollableDetails.horizontal(),
delegate: SimpleTableDelegate(builder: (context, vicinity) {
return Container(
decoration: BoxDecoration(
border: Border.all(),
color: vicinity.xIndex.isEven && vicinity.yIndex.isEven
? Colors.amber[100]
: (vicinity.xIndex.isOdd && vicinity.yIndex.isOdd
? Colors.blueAccent[100]
: null),
),
height: 200.0,
width: 200.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Checkbox(value: false, onChanged: (value) {}),
Text(vicinity.toString()),
],
),
);
}),
),
),
);
}
}
class SimpleTableDelegate extends TwoDimensionalChildBuilderDelegate {
SimpleTableDelegate({required super.builder});
}
class SimpleTableView extends TwoDimensionalScrollView {
const SimpleTableView({
super.key,
super.primary,
super.mainAxis = Axis.vertical,
super.verticalDetails = const ScrollableDetails.vertical(),
super.horizontalDetails = const ScrollableDetails.horizontal(),
required super.delegate,
super.cacheExtent,
super.diagonalDragBehavior = DiagonalDragBehavior.none,
super.dragStartBehavior = DragStartBehavior.start,
super.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
super.clipBehavior = Clip.hardEdge,
});
@override
Widget buildViewport(BuildContext context, ViewportOffset verticalOffset,
ViewportOffset horizontalOffset) {
return SimpleTableViewport(
horizontalOffset: horizontalOffset,
horizontalAxisDirection: horizontalDetails.direction,
verticalOffset: verticalOffset,
verticalAxisDirection: verticalDetails.direction,
mainAxis: mainAxis,
delegate: delegate,
cacheExtent: cacheExtent,
clipBehavior: clipBehavior,
);
}
}
class SimpleTableViewport extends TwoDimensionalViewport {
const SimpleTableViewport({
super.key,
required super.verticalOffset,
required super.verticalAxisDirection,
required super.horizontalOffset,
required super.horizontalAxisDirection,
required super.delegate,
required super.mainAxis,
super.cacheExtent,
super.clipBehavior = Clip.hardEdge,
});
@override
SimpleTableDelegate get delegate => super.delegate as SimpleTableDelegate;
@override
RenderTwoDimensionalViewport createRenderObject(BuildContext context) {
return RenderSimpleTableViewport(
horizontalOffset: horizontalOffset,
horizontalAxisDirection: horizontalAxisDirection,
verticalOffset: verticalOffset,
verticalAxisDirection: verticalAxisDirection,
mainAxis: mainAxis,
delegate: delegate,
childManager: context as TwoDimensionalChildManager,
cacheExtent: cacheExtent,
clipBehavior: clipBehavior,
);
}
@override
void updateRenderObject(
BuildContext context, RenderSimpleTableViewport renderObject) {
renderObject
..horizontalOffset = horizontalOffset
..horizontalAxisDirection = horizontalAxisDirection
..verticalOffset = verticalOffset
..verticalAxisDirection = verticalAxisDirection
..mainAxis = mainAxis
..delegate = delegate
..cacheExtent = cacheExtent
..clipBehavior = clipBehavior;
}
}
class RenderSimpleTableViewport extends RenderTwoDimensionalViewport {
RenderSimpleTableViewport({
required super.horizontalOffset,
required super.horizontalAxisDirection,
required super.verticalOffset,
required super.verticalAxisDirection,
required super.delegate,
required super.mainAxis,
required super.childManager,
super.cacheExtent,
super.clipBehavior = Clip.hardEdge,
});
@override
void layoutChildSequence() {
// Every child is 200x200 square
final double horizontalPixels = horizontalOffset.pixels;
final double verticalPixels = verticalOffset.pixels;
final int leadingColumn = math.max((horizontalPixels / 200).floor(), 0);
final int trailingColumn = math.min(
((horizontalPixels + viewportDimension.width + cacheExtent) / 200).ceil(),
99,
);
final int leadingRow = math.max((verticalPixels / 200).floor(), 0);
final int trailingRow = math.min(
((verticalPixels + viewportDimension.height + cacheExtent) / 200).ceil(),
99,
);
double xLayoutOffset = (leadingColumn * 200) - horizontalOffset.pixels;
for (int column = leadingColumn; column <= trailingColumn; column++) {
double yLayoutOffset = (leadingRow * 200) - verticalOffset.pixels;
for (int row = leadingRow; row <= trailingRow; row++) {
final ChildVicinity vicinity = ChildVicinity(xIndex: column, yIndex: row);
final RenderBox child = buildOrObtainChildFor(vicinity)!;
child.layout(constraints, parentUsesSize: true);
parentDataOf(child).layoutOffset = Offset(xLayoutOffset, yLayoutOffset);
yLayoutOffset += 200;
}
xLayoutOffset += 200;
}
verticalOffset.applyContentDimensions(
0,
200 * 100 - viewportDimension.height,
);
horizontalOffset.applyContentDimensions(
0,
200 * 100 - viewportDimension.width,
);
}
}
I have a fix on the way...
TahaTesser
Metadata
Metadata
Assignees
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listf: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.waiting for PR to land (fixed)A fix is in flightA fix is in flight
Type
Projects
Status
Done

