| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import '../rendering/rendering_tester.dart' show TestCallbackPainter; |
| |
| class TestPaintingContext implements PaintingContext { |
| final List<Invocation> invocations = <Invocation>[]; |
| |
| @override |
| void noSuchMethod(Invocation invocation) { |
| invocations.add(invocation); |
| } |
| } |
| |
| void main() { |
| testWidgets('Can construct an empty Stack', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack(), |
| ), |
| ); |
| }); |
| |
| testWidgets('Can construct an empty Centered Stack', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center(child: Stack()), |
| ), |
| ); |
| }); |
| |
| testWidgets('Can change position data', (WidgetTester tester) async { |
| const Key key = Key('container'); |
| |
| await tester.pumpWidget( |
| Stack( |
| alignment: Alignment.topLeft, |
| children: const <Widget>[ |
| Positioned( |
| left: 10.0, |
| child: SizedBox( |
| key: key, |
| width: 10.0, |
| height: 10.0, |
| ), |
| ), |
| ], |
| ), |
| ); |
| |
| Element container; |
| StackParentData parentData; |
| |
| container = tester.element(find.byKey(key)); |
| parentData = container.renderObject!.parentData! as StackParentData; |
| expect(parentData.top, isNull); |
| expect(parentData.right, isNull); |
| expect(parentData.bottom, isNull); |
| expect(parentData.left, equals(10.0)); |
| expect(parentData.width, isNull); |
| expect(parentData.height, isNull); |
| |
| await tester.pumpWidget( |
| Stack( |
| alignment: Alignment.topLeft, |
| children: const <Widget>[ |
| Positioned( |
| right: 10.0, |
| child: SizedBox( |
| key: key, |
| width: 10.0, |
| height: 10.0, |
| ), |
| ), |
| ], |
| ), |
| ); |
| |
| container = tester.element(find.byKey(key)); |
| parentData = container.renderObject!.parentData! as StackParentData; |
| expect(parentData.top, isNull); |
| expect(parentData.right, equals(10.0)); |
| expect(parentData.bottom, isNull); |
| expect(parentData.left, isNull); |
| expect(parentData.width, isNull); |
| expect(parentData.height, isNull); |
| }); |
| |
| testWidgets('Can remove parent data', (WidgetTester tester) async { |
| const Key key = Key('container'); |
| const SizedBox sizedBox = SizedBox(key: key, width: 10.0, height: 10.0); |
| |
| await tester.pumpWidget( |
| Stack( |
| textDirection: TextDirection.ltr, |
| children: const <Widget>[ Positioned(left: 10.0, child: sizedBox) ], |
| ), |
| ); |
| Element containerElement = tester.element(find.byKey(key)); |
| |
| StackParentData parentData; |
| parentData = containerElement.renderObject!.parentData! as StackParentData; |
| expect(parentData.top, isNull); |
| expect(parentData.right, isNull); |
| expect(parentData.bottom, isNull); |
| expect(parentData.left, equals(10.0)); |
| expect(parentData.width, isNull); |
| expect(parentData.height, isNull); |
| |
| await tester.pumpWidget( |
| Stack( |
| textDirection: TextDirection.ltr, |
| children: const <Widget>[ sizedBox ], |
| ), |
| ); |
| containerElement = tester.element(find.byKey(key)); |
| |
| parentData = containerElement.renderObject!.parentData! as StackParentData; |
| expect(parentData.top, isNull); |
| expect(parentData.right, isNull); |
| expect(parentData.bottom, isNull); |
| expect(parentData.left, isNull); |
| expect(parentData.width, isNull); |
| expect(parentData.height, isNull); |
| }); |
| |
| testWidgets('Can align non-positioned children (LTR)', (WidgetTester tester) async { |
| const Key child0Key = Key('child0'); |
| const Key child1Key = Key('child1'); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: Stack( |
| alignment: Alignment.center, |
| children: const <Widget>[ |
| SizedBox(key: child0Key, width: 20.0, height: 20.0), |
| SizedBox(key: child1Key, width: 10.0, height: 10.0), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| final Element child0 = tester.element(find.byKey(child0Key)); |
| final StackParentData child0RenderObjectParentData = child0.renderObject!.parentData! as StackParentData; |
| expect(child0RenderObjectParentData.offset, equals(Offset.zero)); |
| |
| final Element child1 = tester.element(find.byKey(child1Key)); |
| final StackParentData child1RenderObjectParentData = child1.renderObject!.parentData! as StackParentData; |
| expect(child1RenderObjectParentData.offset, equals(const Offset(5.0, 5.0))); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: Stack( |
| alignment: AlignmentDirectional.bottomEnd, |
| children: const <Widget>[ |
| SizedBox(key: child0Key, width: 20.0, height: 20.0), |
| SizedBox(key: child1Key, width: 10.0, height: 10.0), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| expect(child0RenderObjectParentData.offset, equals(Offset.zero)); |
| expect(child1RenderObjectParentData.offset, equals(const Offset(10.0, 10.0))); |
| }); |
| |
| testWidgets('Can align non-positioned children (RTL)', (WidgetTester tester) async { |
| const Key child0Key = Key('child0'); |
| const Key child1Key = Key('child1'); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.rtl, |
| child: Center( |
| child: Stack( |
| alignment: Alignment.center, |
| children: const <Widget>[ |
| SizedBox(key: child0Key, width: 20.0, height: 20.0), |
| SizedBox(key: child1Key, width: 10.0, height: 10.0), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| final Element child0 = tester.element(find.byKey(child0Key)); |
| final StackParentData child0RenderObjectParentData = child0.renderObject!.parentData! as StackParentData; |
| expect(child0RenderObjectParentData.offset, equals(Offset.zero)); |
| |
| final Element child1 = tester.element(find.byKey(child1Key)); |
| final StackParentData child1RenderObjectParentData = child1.renderObject!.parentData! as StackParentData; |
| expect(child1RenderObjectParentData.offset, equals(const Offset(5.0, 5.0))); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.rtl, |
| child: Center( |
| child: Stack( |
| alignment: AlignmentDirectional.bottomEnd, |
| children: const <Widget>[ |
| SizedBox(key: child0Key, width: 20.0, height: 20.0), |
| SizedBox(key: child1Key, width: 10.0, height: 10.0), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| expect(child0RenderObjectParentData.offset, equals(Offset.zero)); |
| expect(child1RenderObjectParentData.offset, equals(const Offset(0.0, 10.0))); |
| }); |
| |
| testWidgets('Can construct an empty IndexedStack', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: IndexedStack(), |
| ), |
| ); |
| }); |
| |
| testWidgets('Can construct an empty Centered IndexedStack', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center(child: IndexedStack()), |
| ), |
| ); |
| }); |
| |
| testWidgets('Can construct an IndexedStack', (WidgetTester tester) async { |
| const int itemCount = 3; |
| late List<int> itemsPainted; |
| |
| Widget buildFrame(int index) { |
| itemsPainted = <int>[]; |
| final List<Widget> items = List<Widget>.generate(itemCount, (int i) { |
| return CustomPaint( |
| painter: TestCallbackPainter( |
| onPaint: () { itemsPainted.add(i); }, |
| ), |
| child: Text('$i', textDirection: TextDirection.ltr), |
| ); |
| }); |
| return Center( |
| child: IndexedStack( |
| alignment: Alignment.topLeft, |
| index: index, |
| children: items, |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(buildFrame(0)); |
| expect(find.text('0'), findsOneWidget); |
| expect(find.text('1'), findsOneWidget); |
| expect(find.text('2'), findsOneWidget); |
| expect(itemsPainted, equals(<int>[0])); |
| |
| await tester.pumpWidget(buildFrame(1)); |
| expect(itemsPainted, equals(<int>[1])); |
| |
| await tester.pumpWidget(buildFrame(2)); |
| expect(itemsPainted, equals(<int>[2])); |
| }); |
| |
| testWidgets('Can hit test an IndexedStack', (WidgetTester tester) async { |
| const Key key = Key('indexedStack'); |
| const int itemCount = 3; |
| late List<int> itemsTapped; |
| |
| Widget buildFrame(int index) { |
| itemsTapped = <int>[]; |
| final List<Widget> items = List<Widget>.generate(itemCount, (int i) { |
| return GestureDetector(child: Text('$i', textDirection: TextDirection.ltr), onTap: () { itemsTapped.add(i); }); |
| }); |
| return Center( |
| child: IndexedStack( |
| alignment: Alignment.topLeft, |
| key: key, |
| index: index, |
| children: items, |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(buildFrame(0)); |
| expect(itemsTapped, isEmpty); |
| await tester.tap(find.byKey(key)); |
| expect(itemsTapped, <int>[0]); |
| |
| await tester.pumpWidget(buildFrame(2)); |
| expect(itemsTapped, isEmpty); |
| await tester.tap(find.byKey(key)); |
| expect(itemsTapped, <int>[2]); |
| }); |
| |
| testWidgets('Can set width and height', (WidgetTester tester) async { |
| const Key key = Key('container'); |
| |
| const BoxDecoration kBoxDecoration = BoxDecoration( |
| color: Color(0xFF00FF00), |
| ); |
| |
| await tester.pumpWidget( |
| Stack( |
| textDirection: TextDirection.ltr, |
| children: const <Widget>[ |
| Positioned( |
| left: 10.0, |
| width: 11.0, |
| height: 12.0, |
| child: DecoratedBox(key: key, decoration: kBoxDecoration), |
| ), |
| ], |
| ), |
| ); |
| |
| Element box; |
| RenderBox renderBox; |
| StackParentData parentData; |
| |
| box = tester.element(find.byKey(key)); |
| renderBox = box.renderObject! as RenderBox; |
| parentData = renderBox.parentData! as StackParentData; |
| expect(parentData.top, isNull); |
| expect(parentData.right, isNull); |
| expect(parentData.bottom, isNull); |
| expect(parentData.left, equals(10.0)); |
| expect(parentData.width, equals(11.0)); |
| expect(parentData.height, equals(12.0)); |
| expect(parentData.offset.dx, equals(10.0)); |
| expect(parentData.offset.dy, equals(0.0)); |
| expect(renderBox.size.width, equals(11.0)); |
| expect(renderBox.size.height, equals(12.0)); |
| |
| await tester.pumpWidget( |
| Stack( |
| textDirection: TextDirection.ltr, |
| children: const <Widget>[ |
| Positioned( |
| right: 10.0, |
| width: 11.0, |
| height: 12.0, |
| child: DecoratedBox(key: key, decoration: kBoxDecoration), |
| ), |
| ], |
| ), |
| ); |
| |
| box = tester.element(find.byKey(key)); |
| renderBox = box.renderObject! as RenderBox; |
| parentData = renderBox.parentData! as StackParentData; |
| expect(parentData.top, isNull); |
| expect(parentData.right, equals(10.0)); |
| expect(parentData.bottom, isNull); |
| expect(parentData.left, isNull); |
| expect(parentData.width, equals(11.0)); |
| expect(parentData.height, equals(12.0)); |
| expect(parentData.offset.dx, equals(779.0)); |
| expect(parentData.offset.dy, equals(0.0)); |
| expect(renderBox.size.width, equals(11.0)); |
| expect(renderBox.size.height, equals(12.0)); |
| }); |
| |
| testWidgets('Can set and update clipBehavior', (WidgetTester tester) async { |
| await tester.pumpWidget(Stack(textDirection: TextDirection.ltr)); |
| final RenderStack renderObject = tester.allRenderObjects.whereType<RenderStack>().first; |
| expect(renderObject.clipBehavior, equals(Clip.hardEdge)); |
| |
| await tester.pumpWidget(Stack(textDirection: TextDirection.ltr)); |
| expect(renderObject.clipBehavior, equals(Clip.hardEdge)); |
| }); |
| |
| testWidgets('Clip.none is respected by describeApproximateClip', (WidgetTester tester) async { |
| await tester.pumpWidget(Stack( |
| textDirection: TextDirection.ltr, |
| children: const <Widget>[Positioned(left: 1000, right: 2000, child: SizedBox(width: 2000, height: 2000))], |
| )); |
| final RenderStack renderObject = tester.allRenderObjects.whereType<RenderStack>().first; |
| expect(renderObject.clipBehavior, equals(Clip.hardEdge)); |
| |
| bool visited = false; |
| renderObject.visitChildren((RenderObject child) { |
| visited = true; |
| expect(renderObject.describeApproximatePaintClip(child), const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)); |
| }); |
| expect(visited, true); |
| visited = false; |
| renderObject.clipBehavior = Clip.none; |
| renderObject.visitChildren((RenderObject child) { |
| visited = true; |
| expect(renderObject.describeApproximatePaintClip(child), null); |
| }); |
| expect(visited, true); |
| }); |
| |
| testWidgets('IndexedStack with null index', (WidgetTester tester) async { |
| bool? tapped; |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: IndexedStack( |
| index: null, |
| children: <Widget>[ |
| GestureDetector( |
| behavior: HitTestBehavior.opaque, |
| onTap: () { tapped = true; }, |
| child: const SizedBox( |
| width: 200.0, |
| height: 200.0, |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| await tester.tap(find.byType(IndexedStack), warnIfMissed: false); |
| final RenderBox box = tester.renderObject(find.byType(IndexedStack)); |
| expect(box.size, equals(const Size(200.0, 200.0))); |
| expect(tapped, isNull); |
| }); |
| |
| testWidgets('Stack clip test', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: Stack( |
| children: const <Widget>[ |
| SizedBox( |
| width: 100.0, |
| height: 100.0, |
| ), |
| Positioned( |
| top: 0.0, |
| left: 0.0, |
| child: SizedBox( |
| width: 200.0, |
| height: 200.0, |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| RenderBox box = tester.renderObject(find.byType(Stack)); |
| TestPaintingContext context = TestPaintingContext(); |
| box.paint(context, Offset.zero); |
| expect(context.invocations.first.memberName, equals(#pushClipRect)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: Stack( |
| clipBehavior: Clip.none, |
| children: const <Widget>[ |
| SizedBox( |
| width: 100.0, |
| height: 100.0, |
| ), |
| Positioned( |
| top: 0.0, |
| left: 0.0, |
| child: SizedBox( |
| width: 200.0, |
| height: 200.0, |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| box = tester.renderObject(find.byType(Stack)); |
| context = TestPaintingContext(); |
| box.paint(context, Offset.zero); |
| expect(context.invocations.first.memberName, equals(#paintChild)); |
| }); |
| |
| testWidgets('Stack sizing: default', (WidgetTester tester) async { |
| final List<String> logs = <String>[]; |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: ConstrainedBox( |
| constraints: const BoxConstraints( |
| minWidth: 2.0, |
| maxWidth: 3.0, |
| minHeight: 5.0, |
| maxHeight: 7.0, |
| ), |
| child: Stack( |
| children: <Widget>[ |
| LayoutBuilder( |
| builder: (BuildContext context, BoxConstraints constraints) { |
| logs.add(constraints.toString()); |
| return const Placeholder(); |
| }, |
| ), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| expect(logs, <String>['BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)']); |
| }); |
| |
| testWidgets('Stack sizing: explicit', (WidgetTester tester) async { |
| final List<String> logs = <String>[]; |
| Widget buildStack(StackFit sizing) { |
| return Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: ConstrainedBox( |
| constraints: const BoxConstraints( |
| minWidth: 2.0, |
| maxWidth: 3.0, |
| minHeight: 5.0, |
| maxHeight: 7.0, |
| ), |
| child: Stack( |
| fit: sizing, |
| children: <Widget>[ |
| LayoutBuilder( |
| builder: (BuildContext context, BoxConstraints constraints) { |
| logs.add(constraints.toString()); |
| return const Placeholder(); |
| }, |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| } |
| await tester.pumpWidget(buildStack(StackFit.loose)); |
| logs.add('=1='); |
| await tester.pumpWidget(buildStack(StackFit.expand)); |
| logs.add('=2='); |
| await tester.pumpWidget(buildStack(StackFit.passthrough)); |
| expect(logs, <String>[ |
| 'BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)', |
| '=1=', |
| 'BoxConstraints(w=3.0, h=7.0)', |
| '=2=', |
| 'BoxConstraints(2.0<=w<=3.0, 5.0<=h<=7.0)', |
| ]); |
| }); |
| |
| testWidgets('Positioned.directional control test', (WidgetTester tester) async { |
| final Key key = UniqueKey(); |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack( |
| children: <Widget>[ |
| Positioned.directional( |
| textDirection: TextDirection.rtl, |
| start: 50.0, |
| child: SizedBox(key: key, width: 75.0, height: 175.0), |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| expect(tester.getTopLeft(find.byKey(key)), const Offset(675.0, 0.0)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack( |
| children: <Widget>[ |
| Positioned.directional( |
| textDirection: TextDirection.ltr, |
| start: 50.0, |
| child: SizedBox(key: key, width: 75.0, height: 175.0), |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0)); |
| }); |
| |
| testWidgets('PositionedDirectional control test', (WidgetTester tester) async { |
| final Key key = UniqueKey(); |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.rtl, |
| child: Stack( |
| children: <Widget>[ |
| PositionedDirectional( |
| start: 50.0, |
| child: SizedBox(key: key, width: 75.0, height: 175.0), |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| expect(tester.getTopLeft(find.byKey(key)), const Offset(675.0, 0.0)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack( |
| children: <Widget>[ |
| PositionedDirectional( |
| start: 50.0, |
| child: SizedBox(key: key, width: 75.0, height: 175.0), |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0)); |
| }); |
| |
| testWidgets('Can change the text direction of a Stack', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Stack( |
| alignment: Alignment.center, |
| ), |
| ); |
| await tester.pumpWidget( |
| Stack( |
| textDirection: TextDirection.rtl, |
| ), |
| ); |
| await tester.pumpWidget( |
| Stack( |
| alignment: Alignment.center, |
| ), |
| ); |
| }); |
| |
| testWidgets('Alignment with partially-positioned children', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.rtl, |
| child: Stack( |
| alignment: Alignment.center, |
| children: const <Widget>[ |
| SizedBox(width: 100.0, height: 100.0), |
| Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| ], |
| ), |
| ), |
| ); |
| expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(350.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack( |
| alignment: Alignment.center, |
| children: const <Widget>[ |
| SizedBox(width: 100.0, height: 100.0), |
| Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| ], |
| ), |
| ), |
| ); |
| expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(350.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack( |
| alignment: Alignment.bottomRight, |
| children: const <Widget>[ |
| SizedBox(width: 100.0, height: 100.0), |
| Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| ], |
| ), |
| ), |
| ); |
| expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack( |
| alignment: Alignment.topLeft, |
| children: const <Widget>[ |
| SizedBox(width: 100.0, height: 100.0), |
| Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)), |
| ], |
| ), |
| ), |
| ); |
| expect(tester.getRect(find.byType(SizedBox).at(0)), const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(1)), const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(2)), const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(3)), const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(4)), const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(5)), const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(6)), const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)); |
| expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0)); |
| }); |
| |
| testWidgets('Stack error messages', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Stack(), |
| ); |
| expect( |
| tester.takeException().toString(), |
| 'No Directionality widget found.\n' |
| "Stack widgets require a Directionality widget ancestor to resolve the 'alignment' argument.\n" |
| "The default value for 'alignment' is AlignmentDirectional.topStart, which requires a text direction.\n" |
| 'The specific widget that could not find a Directionality ancestor was:\n' |
| ' Stack\n' |
| 'The ownership chain for the affected widget is: "Stack ← [root]"\n' |
| 'Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the ' |
| 'top of your application widget tree. It determines the ambient reading direction and is used, for ' |
| 'example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve ' |
| 'EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.\n' |
| 'Instead of providing a Directionality widget, another solution would be passing a non-directional ' |
| "'alignment', or an explicit 'textDirection', to the Stack.", |
| ); |
| }); |
| |
| testWidgets('Can update clipBehavior of IndexedStack', |
| (WidgetTester tester) async { |
| await tester.pumpWidget(IndexedStack(textDirection: TextDirection.ltr)); |
| final RenderIndexedStack renderObject = |
| tester.renderObject<RenderIndexedStack>(find.byType(IndexedStack)); |
| expect(renderObject.clipBehavior, equals(Clip.hardEdge)); |
| |
| // Update clipBehavior to Clip.antiAlias |
| |
| await tester.pumpWidget(IndexedStack( |
| textDirection: TextDirection.ltr, |
| clipBehavior: Clip.antiAlias, |
| )); |
| final RenderIndexedStack renderIndexedObject = |
| tester.renderObject<RenderIndexedStack>(find.byType(IndexedStack)); |
| expect(renderIndexedObject.clipBehavior, equals(Clip.antiAlias)); |
| }); |
| |
| testWidgets('IndexedStack sizing: explicit', (WidgetTester tester) async { |
| final List<String> logs = <String>[]; |
| Widget buildIndexedStack(StackFit sizing) { |
| return Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: ConstrainedBox( |
| constraints: const BoxConstraints( |
| minWidth: 2.0, |
| maxWidth: 3.0, |
| minHeight: 5.0, |
| maxHeight: 7.0, |
| ), |
| child: IndexedStack( |
| sizing: sizing, |
| children: <Widget>[ |
| LayoutBuilder( |
| builder: (BuildContext context, BoxConstraints constraints) { |
| logs.add(constraints.toString()); |
| return const Placeholder(); |
| }, |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| } |
| await tester.pumpWidget(buildIndexedStack(StackFit.loose)); |
| logs.add('=1='); |
| await tester.pumpWidget(buildIndexedStack(StackFit.expand)); |
| logs.add('=2='); |
| await tester.pumpWidget(buildIndexedStack(StackFit.passthrough)); |
| expect(logs, <String>[ |
| 'BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)', |
| '=1=', |
| 'BoxConstraints(w=3.0, h=7.0)', |
| '=2=', |
| 'BoxConstraints(2.0<=w<=3.0, 5.0<=h<=7.0)', |
| ]); |
| }); |
| } |