Unverified Commit 9aea03f4 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Implement PageView using SliverLayoutBuilder, Deprecate RenderSliverFillViewport (#37024)

parent bf097eec
...@@ -27,6 +27,7 @@ import 'sliver_multi_box_adaptor.dart'; ...@@ -27,6 +27,7 @@ import 'sliver_multi_box_adaptor.dart';
/// * [RenderSliverFixedExtentList], which has a configurable [itemExtent]. /// * [RenderSliverFixedExtentList], which has a configurable [itemExtent].
/// * [RenderSliverList], which does not require its children to have the same /// * [RenderSliverList], which does not require its children to have the same
/// extent in the main axis. /// extent in the main axis.
@Deprecated('Use SliverLayoutBuilder instead.')
class RenderSliverFillViewport extends RenderSliverFixedExtentBoxAdaptor { class RenderSliverFillViewport extends RenderSliverFixedExtentBoxAdaptor {
/// Creates a sliver that contains multiple box children that each fill the /// Creates a sliver that contains multiple box children that each fill the
/// viewport. /// viewport.
...@@ -105,8 +106,6 @@ class RenderSliverFillViewport extends RenderSliverFixedExtentBoxAdaptor { ...@@ -105,8 +106,6 @@ class RenderSliverFillViewport extends RenderSliverFixedExtentBoxAdaptor {
/// ///
/// See also: /// See also:
/// ///
/// * [RenderSliverFillViewport], which sizes its children based on the
/// size of the viewport, regardless of what else is in the scroll view.
/// * [RenderSliverList], which shows a list of variable-sized children in a /// * [RenderSliverList], which shows a list of variable-sized children in a
/// viewport. /// viewport.
class RenderSliverFillRemaining extends RenderSliverSingleBoxAdapter { class RenderSliverFillRemaining extends RenderSliverSingleBoxAdapter {
......
...@@ -930,8 +930,8 @@ class RawGestureDetectorState extends State<RawGestureDetector> { ...@@ -930,8 +930,8 @@ class RawGestureDetectorState extends State<RawGestureDetector> {
} }
} }
/// This method can be called outside of the build phase to filter the list of /// This method can be called to filter the list of available semantic actions,
/// available semantic actions. /// after the render object was created.
/// ///
/// The actual filtering is happening in the next frame and a frame will be /// The actual filtering is happening in the next frame and a frame will be
/// scheduled if non is pending. /// scheduled if non is pending.
...@@ -942,20 +942,21 @@ class RawGestureDetectorState extends State<RawGestureDetector> { ...@@ -942,20 +942,21 @@ class RawGestureDetectorState extends State<RawGestureDetector> {
/// If this is never called, then the actions are not filtered. If the list of /// If this is never called, then the actions are not filtered. If the list of
/// actions to filter changes, it must be called again. /// actions to filter changes, it must be called again.
void replaceSemanticsActions(Set<SemanticsAction> actions) { void replaceSemanticsActions(Set<SemanticsAction> actions) {
if (widget.excludeFromSemantics)
return;
final RenderSemanticsGestureHandler semanticsGestureHandler = context.findRenderObject();
assert(() { assert(() {
final Element element = context; if (semanticsGestureHandler == null) {
if (element.owner.debugBuilding) {
throw FlutterError( throw FlutterError(
'Unexpected call to replaceSemanticsActions() method of RawGestureDetectorState.\n' 'Unexpected call to replaceSemanticsActions() method of RawGestureDetectorState.\n'
'The replaceSemanticsActions() method can only be called outside of the build phase.' 'The replaceSemanticsActions() method can only be called after the RenderSemanticsGestureHandler has been created.'
); );
} }
return true; return true;
}()); }());
if (!widget.excludeFromSemantics) {
final RenderSemanticsGestureHandler semanticsGestureHandler = context.findRenderObject(); semanticsGestureHandler.validActions = actions; // will call _markNeedsSemanticsUpdate(), if required.
semanticsGestureHandler.validActions = actions; // will call _markNeedsSemanticsUpdate(), if required.
}
} }
@override @override
......
...@@ -368,8 +368,16 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri ...@@ -368,8 +368,16 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
forcePixels(getPixelsFromPage(oldPage)); forcePixels(getPixelsFromPage(oldPage));
} }
// The amount of offset that will be added to [minScrollExtent] and subtracted
// from [maxScrollExtent], such that every page will properly snap to the center
// of the viewport when viewportFraction is greater than 1.
//
// The value is 0 if viewportFraction is less than or equal to 1, larger than 0
// otherwise.
double get _initialPageOffset => math.max(0, viewportDimension * (viewportFraction - 1) / 2);
double getPageFromPixels(double pixels, double viewportDimension) { double getPageFromPixels(double pixels, double viewportDimension) {
final double actual = math.max(0.0, pixels) / math.max(1.0, viewportDimension * viewportFraction); final double actual = math.max(0, pixels - _initialPageOffset) / math.max(1.0, viewportDimension * viewportFraction);
final double round = actual.roundToDouble(); final double round = actual.roundToDouble();
if ((actual - round).abs() < precisionErrorTolerance) { if ((actual - round).abs() < precisionErrorTolerance) {
return round; return round;
...@@ -378,7 +386,7 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri ...@@ -378,7 +386,7 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
} }
double getPixelsFromPage(double page) { double getPixelsFromPage(double page) {
return page * viewportDimension * viewportFraction; return page * viewportDimension * viewportFraction + _initialPageOffset;
} }
@override @override
...@@ -420,6 +428,15 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri ...@@ -420,6 +428,15 @@ class _PagePosition extends ScrollPositionWithSingleContext implements PageMetri
return result; return result;
} }
@override
bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) {
final double newMinScrollExtent = minScrollExtent + _initialPageOffset;
return super.applyContentDimensions(
newMinScrollExtent,
math.max(newMinScrollExtent, maxScrollExtent - _initialPageOffset),
);
}
@override @override
PageMetrics copyWith({ PageMetrics copyWith({
double minScrollExtent, double minScrollExtent,
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:collection' show SplayTreeMap, HashMap; import 'dart:collection' show SplayTreeMap, HashMap;
import 'dart:math' as math show max;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
...@@ -10,6 +11,7 @@ import 'package:flutter/rendering.dart'; ...@@ -10,6 +11,7 @@ import 'package:flutter/rendering.dart';
import 'automatic_keep_alive.dart'; import 'automatic_keep_alive.dart';
import 'basic.dart'; import 'basic.dart';
import 'framework.dart'; import 'framework.dart';
import 'sliver_layout_builder.dart';
export 'package:flutter/rendering.dart' show export 'package:flutter/rendering.dart' show
SliverGridDelegate, SliverGridDelegate,
...@@ -717,6 +719,7 @@ abstract class SliverMultiBoxAdaptorWidget extends SliverWithKeepAliveWidget { ...@@ -717,6 +719,7 @@ abstract class SliverMultiBoxAdaptorWidget extends SliverWithKeepAliveWidget {
}) : assert(delegate != null), }) : assert(delegate != null),
super(key: key); super(key: key);
/// {@template flutter.widgets.sliverChildDelegate}
/// The delegate that provides the children for this widget. /// The delegate that provides the children for this widget.
/// ///
/// The children are constructed lazily using this widget to avoid creating /// The children are constructed lazily using this widget to avoid creating
...@@ -727,6 +730,7 @@ abstract class SliverMultiBoxAdaptorWidget extends SliverWithKeepAliveWidget { ...@@ -727,6 +730,7 @@ abstract class SliverMultiBoxAdaptorWidget extends SliverWithKeepAliveWidget {
/// * [SliverChildBuilderDelegate] and [SliverChildListDelegate], which are /// * [SliverChildBuilderDelegate] and [SliverChildListDelegate], which are
/// commonly used subclasses of [SliverChildDelegate] that use a builder /// commonly used subclasses of [SliverChildDelegate] that use a builder
/// callback and an explicit child list, respectively. /// callback and an explicit child list, respectively.
/// {@endtemplate}
final SliverChildDelegate delegate; final SliverChildDelegate delegate;
@override @override
...@@ -1030,15 +1034,16 @@ class SliverGrid extends SliverMultiBoxAdaptorWidget { ...@@ -1030,15 +1034,16 @@ class SliverGrid extends SliverMultiBoxAdaptorWidget {
/// the main axis extent of each item. /// the main axis extent of each item.
/// * [SliverList], which does not require its children to have the same /// * [SliverList], which does not require its children to have the same
/// extent in the main axis. /// extent in the main axis.
class SliverFillViewport extends SliverMultiBoxAdaptorWidget { class SliverFillViewport extends StatelessWidget {
/// Creates a sliver whose box children that each fill the viewport. /// Creates a sliver whose box children that each fill the viewport.
const SliverFillViewport({ const SliverFillViewport({
Key key, Key key,
@required SliverChildDelegate delegate, @required this.delegate,
this.viewportFraction = 1.0, this.viewportFraction = 1.0,
}) : assert(viewportFraction != null), }) : assert(viewportFraction != null),
assert(viewportFraction > 0.0), assert(viewportFraction > 0.0),
super(key: key, delegate: delegate); assert(delegate != null),
super(key: key);
/// The fraction of the viewport that each child should fill in the main axis. /// The fraction of the viewport that each child should fill in the main axis.
/// ///
...@@ -1047,15 +1052,34 @@ class SliverFillViewport extends SliverMultiBoxAdaptorWidget { ...@@ -1047,15 +1052,34 @@ class SliverFillViewport extends SliverMultiBoxAdaptorWidget {
/// the viewport in the main axis. /// the viewport in the main axis.
final double viewportFraction; final double viewportFraction;
@override /// {@macro flutter.widgets.sliverChildDelegate}
RenderSliverFillViewport createRenderObject(BuildContext context) { final SliverChildDelegate delegate;
final SliverMultiBoxAdaptorElement element = context;
return RenderSliverFillViewport(childManager: element, viewportFraction: viewportFraction);
}
@override @override
void updateRenderObject(BuildContext context, RenderSliverFillViewport renderObject) { Widget build(BuildContext context) {
renderObject.viewportFraction = viewportFraction; return SliverLayoutBuilder(
builder: (BuildContext context, SliverConstraints constraints) {
final double fixedExtent = constraints.viewportMainAxisExtent * viewportFraction;
final double padding = math.max(0, constraints.viewportMainAxisExtent - fixedExtent) / 2;
EdgeInsets sliverPaddingValue;
switch (constraints.axis) {
case Axis.horizontal:
sliverPaddingValue = EdgeInsets.symmetric(horizontal: padding);
break;
case Axis.vertical:
sliverPaddingValue = EdgeInsets.symmetric(vertical: padding);
}
return SliverPadding(
padding: sliverPaddingValue,
sliver: SliverFixedExtentList(
delegate: delegate,
itemExtent: fixedExtent,
),
);
}
);
} }
} }
......
...@@ -24,7 +24,7 @@ void main() { ...@@ -24,7 +24,7 @@ void main() {
offset: ViewportOffset.zero(), offset: ViewportOffset.zero(),
cacheExtent: 0, cacheExtent: 0,
children: <RenderSliver>[ children: <RenderSliver>[
childManager.createRenderSliverFillViewport(), childManager.createRenderSliverFixedExtentList(),
], ],
); );
layout(root); layout(root);
...@@ -52,10 +52,11 @@ class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager { ...@@ -52,10 +52,11 @@ class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
RenderSliverMultiBoxAdaptor _renderObject; RenderSliverMultiBoxAdaptor _renderObject;
List<RenderBox> children; List<RenderBox> children;
RenderSliverFillViewport createRenderSliverFillViewport() { RenderSliverFixedExtentList createRenderSliverFixedExtentList() {
assert(_renderObject == null); assert(_renderObject == null);
_renderObject = RenderSliverFillViewport( _renderObject = RenderSliverFixedExtentList(
childManager: this, childManager: this,
itemExtent: 600,
); );
return _renderObject; return _renderObject;
} }
......
...@@ -394,8 +394,8 @@ void main() { ...@@ -394,8 +394,8 @@ void main() {
return Container( return Container(
height: 200.0, height: 200.0,
color: index % 2 == 0 color: index % 2 == 0
? const Color(0xFF0000FF) ? const Color(0xFF0000FF)
: const Color(0xFF00FF00), : const Color(0xFF00FF00),
child: Text(kStates[index]), child: Text(kStates[index]),
); );
}, },
...@@ -500,8 +500,8 @@ void main() { ...@@ -500,8 +500,8 @@ void main() {
return Container( return Container(
height: 200.0, height: 200.0,
color: index % 2 == 0 color: index % 2 == 0
? const Color(0xFF0000FF) ? const Color(0xFF0000FF)
: const Color(0xFF00FF00), : const Color(0xFF00FF00),
child: Text(kStates[index]), child: Text(kStates[index]),
); );
}, },
...@@ -545,8 +545,8 @@ void main() { ...@@ -545,8 +545,8 @@ void main() {
return Container( return Container(
height: 200.0, height: 200.0,
color: index % 2 == 0 color: index % 2 == 0
? const Color(0xFF0000FF) ? const Color(0xFF0000FF)
: const Color(0xFF00FF00), : const Color(0xFF00FF00),
child: Text(kStates[index]), child: Text(kStates[index]),
); );
}, },
...@@ -565,6 +565,88 @@ void main() { ...@@ -565,6 +565,88 @@ void main() {
expect(tester.getTopLeft(find.text('Hawaii')), const Offset(-100.0, 0.0)); expect(tester.getTopLeft(find.text('Hawaii')), const Offset(-100.0, 0.0));
}); });
testWidgets(
'Updating PageView large viewportFraction',
(WidgetTester tester) async {
Widget build(PageController controller) {
return Directionality(
textDirection: TextDirection.ltr,
child: PageView.builder(
controller: controller,
itemCount: kStates.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 200.0,
color: index % 2 == 0
? const Color(0xFF0000FF)
: const Color(0xFF00FF00),
child: Text(kStates[index]),
);
},
),
);
}
final PageController oldController = PageController(viewportFraction: 5/4);
await tester.pumpWidget(build(oldController));
expect(tester.getTopLeft(find.text('Alabama')), const Offset(-100, 0));
expect(tester.getBottomRight(find.text('Alabama')), const Offset(900.0, 600.0));
final PageController newController = PageController(viewportFraction: 4);
await tester.pumpWidget(build(newController));
newController.jumpToPage(10);
await tester.pump();
expect(tester.getTopLeft(find.text('Hawaii')), const Offset(-(4 - 1) * 800 / 2, 0));
});
testWidgets(
'All visible pages are able to receive touch events',
(WidgetTester tester) async {
final PageController controller = PageController(viewportFraction: 1/4, initialPage: 0);
int tappedIndex;
Widget build() {
return Directionality(
textDirection: TextDirection.ltr,
child: PageView.builder(
controller: controller,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () => tappedIndex = index,
child: SizedBox.expand(child: Text('$index')),
);
},
),
);
}
Iterable<int> visiblePages = const <int> [0, 1, 2];
await tester.pumpWidget(build());
// The first 3 items should be visible and tappable.
for (int index in visiblePages) {
expect(find.text(index.toString()), findsOneWidget);
// The center of page 2's x-coordinate is 800, so we have to manually
// offset it a bit to make sure the tap lands within the screen.
final Offset center = tester.getCenter(find.text('$index')) - const Offset(3, 0);
await tester.tapAt(center);
expect(tappedIndex, index);
}
controller.jumpToPage(19);
await tester.pump();
// The last 3 items should be visible and tappable.
visiblePages = const <int> [17, 18, 19];
for (int index in visiblePages) {
expect(find.text('$index'), findsOneWidget);
await tester.tap(find.text('$index'));
expect(tappedIndex, index);
}
});
testWidgets('PageView does not report page changed on overscroll', (WidgetTester tester) async { testWidgets('PageView does not report page changed on overscroll', (WidgetTester tester) async {
final PageController controller = PageController( final PageController controller = PageController(
initialPage: kStates.length - 1, initialPage: kStates.length - 1,
......
...@@ -64,7 +64,7 @@ void main() { ...@@ -64,7 +64,7 @@ void main() {
expect( expect(
viewport.toStringDeep(minLevel: DiagnosticLevel.info), viewport.toStringDeep(minLevel: DiagnosticLevel.info),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
'RenderSliverFillViewport#00000 relayoutBoundary=up1\n' '_RenderSliverLayoutBuilder#00000 relayoutBoundary=up1\n'
' │ needs compositing\n' ' │ needs compositing\n'
' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n' ' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
' │ constraints: SliverConstraints(AxisDirection.down,\n' ' │ constraints: SliverConstraints(AxisDirection.down,\n'
...@@ -76,58 +76,86 @@ void main() { ...@@ -76,58 +76,86 @@ void main() {
' │ geometry: SliverGeometry(scrollExtent: 12000.0, paintExtent:\n' ' │ geometry: SliverGeometry(scrollExtent: 12000.0, paintExtent:\n'
' │ 600.0, maxPaintExtent: 12000.0, hasVisualOverflow: true,\n' ' │ 600.0, maxPaintExtent: 12000.0, hasVisualOverflow: true,\n'
' │ cacheExtent: 850.0)\n' ' │ cacheExtent: 850.0)\n'
' │ currently live children: 0 to 1\n'
' │\n' ' │\n'
' ├─child with index 0: RenderRepaintBoundary#00000\n' ' └─child: RenderSliverPadding#00000 relayoutBoundary=up2\n'
' │ │ needs compositing\n'
' │ │ parentData: index=0; layoutOffset=0.0\n'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ │ layer: OffsetLayer#00000\n'
' │ │ size: Size(800.0, 600.0)\n'
' │ │ metrics: 66.7% useful (1 bad vs 2 good)\n'
' │ │ diagnosis: insufficient data to draw conclusion (less than five\n'
' │ │ repaints)\n'
' │ │\n'
' │ └─child: RenderParagraph#00000\n'
' │ │ parentData: <none> (can use size)\n'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ │ semantics node: SemanticsNode#2\n'
' │ │ size: Size(800.0, 600.0)\n'
' │ │ textAlign: start\n'
' │ │ textDirection: ltr\n'
' │ │ softWrap: wrapping at box width\n'
' │ │ overflow: clip\n'
' │ │ maxLines: unlimited\n'
' │ ╘═╦══ text ═══\n'
' │ ║ TextSpan:\n'
' │ ║ <all styles inherited>\n'
' │ ║ "0"\n'
' │ ╚═══════════\n'
' └─child with index 1: RenderRepaintBoundary#00000\n'
' │ needs compositing\n' ' │ needs compositing\n'
' │ parentData: index=1; layoutOffset=600.0\n' ' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n' ' │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ layer: OffsetLayer#00000 DETACHED\n' ' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ size: Size(800.0, 600.0)\n' ' │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
' │ metrics: 50.0% useful (1 bad vs 1 good)\n' ' │ crossAxisDirection: AxisDirection.right,\n'
' │ diagnosis: insufficient data to draw conclusion (less than five\n' ' │ viewportMainAxisExtent: 600.0, remainingCacheExtent: 850.0\n'
' │ repaints)\n' ' │ cacheOrigin: 0.0 )\n'
' │ geometry: SliverGeometry(scrollExtent: 12000.0, paintExtent:\n'
' │ 600.0, maxPaintExtent: 12000.0, hasVisualOverflow: true,\n'
' │ cacheExtent: 850.0)\n'
' │ padding: EdgeInsets.zero\n'
' │ textDirection: ltr\n'
' │\n' ' │\n'
' └─child: RenderParagraph#00000\n' ' └─child: RenderSliverFixedExtentList#00000 relayoutBoundary=up3\n'
' │ parentData: <none> (can use size)\n' ' │ needs compositing\n'
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n' ' │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
' │ semantics node: SemanticsNode#3\n' ' │ constraints: SliverConstraints(AxisDirection.down,\n'
' │ size: Size(800.0, 600.0)\n' ' │ GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
' │ textAlign: start\n' ' │ 0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
' │ textDirection: ltr\n' ' │ crossAxisDirection: AxisDirection.right,\n'
' │ softWrap: wrapping at box width\n' ' │ viewportMainAxisExtent: 600.0, remainingCacheExtent: 850.0\n'
' │ overflow: clip\n' ' │ cacheOrigin: 0.0 )\n'
' │ maxLines: unlimited\n' ' │ geometry: SliverGeometry(scrollExtent: 12000.0, paintExtent:\n'
' ╘═╦══ text ═══\n' ' │ 600.0, maxPaintExtent: 12000.0, hasVisualOverflow: true,\n'
' ║ TextSpan:\n' ' │ cacheExtent: 850.0)\n'
' ║ <all styles inherited>\n' ' │ currently live children: 0 to 1\n'
' ║ "1"\n' ' │\n'
' ╚═══════════\n' ' ├─child with index 0: RenderRepaintBoundary#00000\n'
' │ │ needs compositing\n'
' │ │ parentData: index=0; layoutOffset=0.0\n'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ │ layer: OffsetLayer#00000\n'
' │ │ size: Size(800.0, 600.0)\n'
' │ │ metrics: 66.7% useful (1 bad vs 2 good)\n'
' │ │ diagnosis: insufficient data to draw conclusion (less than five\n'
' │ │ repaints)\n'
' │ │\n'
' │ └─child: RenderParagraph#00000\n'
' │ │ parentData: <none> (can use size)\n'
' │ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ │ semantics node: SemanticsNode#2\n'
' │ │ size: Size(800.0, 600.0)\n'
' │ │ textAlign: start\n'
' │ │ textDirection: ltr\n'
' │ │ softWrap: wrapping at box width\n'
' │ │ overflow: clip\n'
' │ │ maxLines: unlimited\n'
' │ ╘═╦══ text ═══\n'
' │ ║ TextSpan:\n'
' │ ║ <all styles inherited>\n'
' │ ║ "0"\n'
' │ ╚═══════════\n'
' └─child with index 1: RenderRepaintBoundary#00000\n'
' │ needs compositing\n'
' │ parentData: index=1; layoutOffset=600.0\n'
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ layer: OffsetLayer#00000 DETACHED\n'
' │ size: Size(800.0, 600.0)\n'
' │ metrics: 50.0% useful (1 bad vs 1 good)\n'
' │ diagnosis: insufficient data to draw conclusion (less than five\n'
' │ repaints)\n'
' │\n'
' └─child: RenderParagraph#00000\n'
' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ semantics node: SemanticsNode#3\n'
' │ size: Size(800.0, 600.0)\n'
' │ textAlign: start\n'
' │ textDirection: ltr\n'
' │ softWrap: wrapping at box width\n'
' │ overflow: clip\n'
' │ maxLines: unlimited\n'
' ╘═╦══ text ═══\n'
' ║ TextSpan:\n'
' ║ <all styles inherited>\n'
' ║ "1"\n'
' ╚═══════════\n'
'' ''
), ),
); );
......
...@@ -462,7 +462,7 @@ class _SwitchingChildBuilderTest extends State<SwitchingChildBuilderTest> { ...@@ -462,7 +462,7 @@ class _SwitchingChildBuilderTest extends State<SwitchingChildBuilderTest> {
childCount: children.length, childCount: children.length,
findChildIndexCallback: (Key key) => _mapKeyToIndex[key] ?? -1, findChildIndexCallback: (Key key) => _mapKeyToIndex[key] ?? -1,
), ),
) ),
], ],
), ),
), ),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment