blob: e08609f5679f5608bd8f41c820edd591b478b551 [file] [log] [blame]
// 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_test/flutter_test.dart';
import 'rendering_tester.dart';
void main() {
TestRenderingFlutterBinding.ensureInitialized();
test('Stack can layout with top, right, bottom, left 0.0', () {
final RenderBox size = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox red = RenderDecoratedBox(
decoration: const BoxDecoration(
color: Color(0xFFFF0000),
),
child: size,
);
final RenderBox green = RenderDecoratedBox(
decoration: const BoxDecoration(
color: Color(0xFFFF0000),
),
);
final RenderBox stack = RenderStack(
textDirection: TextDirection.ltr,
children: <RenderBox>[red, green],
);
final StackParentData greenParentData = green.parentData! as StackParentData;
greenParentData
..top = 0.0
..right = 0.0
..bottom = 0.0
..left = 0.0;
layout(stack, constraints: const BoxConstraints());
expect(stack.size.width, equals(100.0));
expect(stack.size.height, equals(100.0));
expect(red.size.width, equals(100.0));
expect(red.size.height, equals(100.0));
expect(green.size.width, equals(100.0));
expect(green.size.height, equals(100.0));
});
test('Stack can layout with no children', () {
final RenderBox stack = RenderStack(
textDirection: TextDirection.ltr,
children: <RenderBox>[],
);
layout(stack, constraints: BoxConstraints.tight(const Size(100.0, 100.0)));
expect(stack.size.width, equals(100.0));
expect(stack.size.height, equals(100.0));
});
test('Stack has correct clipBehavior', () {
const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
for (final Clip? clip in <Clip?>[null, ...Clip.values]) {
final TestClipPaintingContext context = TestClipPaintingContext();
final RenderBox child = box200x200;
final RenderStack stack;
switch(clip){
case Clip.none:
case Clip.hardEdge:
case Clip.antiAlias:
case Clip.antiAliasWithSaveLayer:
stack = RenderStack(
textDirection: TextDirection.ltr,
children: <RenderBox>[child],
clipBehavior: clip!,
);
break;
case null:
stack = RenderStack(
textDirection: TextDirection.ltr,
children: <RenderBox>[child],
);
break;
}
{ // Make sure that the child is positioned so the stack will consider it as overflowed.
final StackParentData parentData = child.parentData! as StackParentData;
parentData.left = parentData.right = 0;
}
layout(stack, constraints: viewport, phase: EnginePhase.composite, onErrors: expectNoFlutterErrors);
context.paintChild(stack, Offset.zero);
// By default, clipBehavior should be Clip.hardEdge
expect(context.clipBehavior, equals(clip ?? Clip.hardEdge), reason: 'for $clip');
}
});
group('RenderIndexedStack', () {
test('visitChildrenForSemantics only visits displayed child', () {
final RenderBox child1 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox child2 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox child3 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox stack = RenderIndexedStack(
index: 1,
textDirection: TextDirection.ltr,
children: <RenderBox>[child1, child2, child3],
);
final List<RenderObject> visitedChildren = <RenderObject>[];
void visitor(RenderObject child) {
visitedChildren.add(child);
}
stack.visitChildrenForSemantics(visitor);
expect(visitedChildren, hasLength(1));
expect(visitedChildren.first, child2);
});
test('debugDescribeChildren marks invisible children as offstage', () {
final RenderBox child1 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox child2 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox child3 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox stack = RenderIndexedStack(
index: 2,
children: <RenderBox>[child1, child2, child3],
);
final List<DiagnosticsNode> diagnosticNodes = stack.debugDescribeChildren();
expect(diagnosticNodes[0].name, 'child 1');
expect(diagnosticNodes[0].style, DiagnosticsTreeStyle.offstage);
expect(diagnosticNodes[1].name, 'child 2');
expect(diagnosticNodes[1].style, DiagnosticsTreeStyle.offstage);
expect(diagnosticNodes[2].name, 'child 3');
expect(diagnosticNodes[2].style, DiagnosticsTreeStyle.sparse);
});
test('debugDescribeChildren handles a null index', () {
final RenderBox child1 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox child2 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox child3 = RenderConstrainedBox(
additionalConstraints: BoxConstraints.tight(const Size(100.0, 100.0)),
);
final RenderBox stack = RenderIndexedStack(
index: null,
children: <RenderBox>[child1, child2, child3],
);
final List<DiagnosticsNode> diagnosticNodes = stack.debugDescribeChildren();
expect(diagnosticNodes[0].name, 'child 1');
expect(diagnosticNodes[0].style, DiagnosticsTreeStyle.offstage);
expect(diagnosticNodes[1].name, 'child 2');
expect(diagnosticNodes[1].style, DiagnosticsTreeStyle.offstage);
expect(diagnosticNodes[2].name, 'child 3');
expect(diagnosticNodes[2].style, DiagnosticsTreeStyle.offstage);
});
});
test('Stack in Flex can layout with no children', () {
// Render an empty Stack in a Flex
final RenderFlex flex = RenderFlex(
textDirection: TextDirection.ltr,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <RenderBox>[
RenderStack(
textDirection: TextDirection.ltr,
children: <RenderBox>[],
),
]
);
bool stackFlutterErrorThrown = false;
layout(
flex,
constraints: BoxConstraints.tight(const Size(100.0, 100.0)),
onErrors: () {
stackFlutterErrorThrown = true;
}
);
expect(stackFlutterErrorThrown, false);
});
// More tests in ../widgets/stack_test.dart
}