// 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/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; class TestSingleChildLayoutDelegate extends SingleChildLayoutDelegate { late BoxConstraints constraintsFromGetSize; BoxConstraints? constraintsFromGetConstraintsForChild; late Size sizeFromGetPositionForChild; late Size childSizeFromGetPositionForChild; @override Size getSize(BoxConstraints constraints) { if (!RenderObject.debugCheckingIntrinsics) { constraintsFromGetSize = constraints; } return const Size(200.0, 300.0); } @override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { assert(!RenderObject.debugCheckingIntrinsics); constraintsFromGetConstraintsForChild = constraints; return const BoxConstraints(minWidth: 100.0, maxWidth: 150.0, minHeight: 200.0, maxHeight: 400.0); } @override Offset getPositionForChild(Size size, Size childSize) { assert(!RenderObject.debugCheckingIntrinsics); sizeFromGetPositionForChild = size; childSizeFromGetPositionForChild = childSize; return Offset.zero; } bool shouldRelayoutCalled = false; bool shouldRelayoutValue = false; @override bool shouldRelayout(_) { assert(!RenderObject.debugCheckingIntrinsics); shouldRelayoutCalled = true; return shouldRelayoutValue; } } class FixedSizeLayoutDelegate extends SingleChildLayoutDelegate { FixedSizeLayoutDelegate(this.size); final Size size; @override Size getSize(BoxConstraints constraints) => size; @override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { return BoxConstraints.tight(size); } @override bool shouldRelayout(FixedSizeLayoutDelegate oldDelegate) { return size != oldDelegate.size; } } class NotifierLayoutDelegate extends SingleChildLayoutDelegate { NotifierLayoutDelegate(this.size) : super(relayout: size); final ValueNotifier<Size> size; @override Size getSize(BoxConstraints constraints) => size.value; @override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { return BoxConstraints.tight(size.value); } @override bool shouldRelayout(NotifierLayoutDelegate oldDelegate) { return size != oldDelegate.size; } } Widget buildFrame(SingleChildLayoutDelegate delegate) { return Center( child: CustomSingleChildLayout( delegate: delegate, child: Container(), ), ); } void main() { testWidgets('Control test for CustomSingleChildLayout', (WidgetTester tester) async { final TestSingleChildLayoutDelegate delegate = TestSingleChildLayoutDelegate(); await tester.pumpWidget(buildFrame(delegate)); expect(delegate.constraintsFromGetSize.minWidth, 0.0); expect(delegate.constraintsFromGetSize.maxWidth, 800.0); expect(delegate.constraintsFromGetSize.minHeight, 0.0); expect(delegate.constraintsFromGetSize.maxHeight, 600.0); expect(delegate.constraintsFromGetConstraintsForChild!.minWidth, 0.0); expect(delegate.constraintsFromGetConstraintsForChild!.maxWidth, 800.0); expect(delegate.constraintsFromGetConstraintsForChild!.minHeight, 0.0); expect(delegate.constraintsFromGetConstraintsForChild!.maxHeight, 600.0); expect(delegate.sizeFromGetPositionForChild.width, 200.0); expect(delegate.sizeFromGetPositionForChild.height, 300.0); expect(delegate.childSizeFromGetPositionForChild.width, 150.0); expect(delegate.childSizeFromGetPositionForChild.height, 400.0); }); testWidgets('Test SingleChildDelegate shouldRelayout method', (WidgetTester tester) async { TestSingleChildLayoutDelegate delegate = TestSingleChildLayoutDelegate(); await tester.pumpWidget(buildFrame(delegate)); // Layout happened because the delegate was set. expect(delegate.constraintsFromGetConstraintsForChild, isNotNull); // i.e. layout happened expect(delegate.shouldRelayoutCalled, isFalse); // Layout did not happen because shouldRelayout() returned false. delegate = TestSingleChildLayoutDelegate(); delegate.shouldRelayoutValue = false; await tester.pumpWidget(buildFrame(delegate)); expect(delegate.shouldRelayoutCalled, isTrue); expect(delegate.constraintsFromGetConstraintsForChild, isNull); // Layout happened because shouldRelayout() returned true. delegate = TestSingleChildLayoutDelegate(); delegate.shouldRelayoutValue = true; await tester.pumpWidget(buildFrame(delegate)); expect(delegate.shouldRelayoutCalled, isTrue); expect(delegate.constraintsFromGetConstraintsForChild, isNotNull); }); testWidgets('Delegate can change size', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(FixedSizeLayoutDelegate(const Size(100.0, 200.0)))); RenderBox box = tester.renderObject(find.byType(CustomSingleChildLayout)); expect(box.size, equals(const Size(100.0, 200.0))); await tester.pumpWidget(buildFrame(FixedSizeLayoutDelegate(const Size(150.0, 240.0)))); box = tester.renderObject(find.byType(CustomSingleChildLayout)); expect(box.size, equals(const Size(150.0, 240.0))); }); testWidgets('Can use listener for relayout', (WidgetTester tester) async { final ValueNotifier<Size> size = ValueNotifier<Size>(const Size(100.0, 200.0)); await tester.pumpWidget(buildFrame(NotifierLayoutDelegate(size))); RenderBox box = tester.renderObject(find.byType(CustomSingleChildLayout)); expect(box.size, equals(const Size(100.0, 200.0))); size.value = const Size(150.0, 240.0); await tester.pump(); box = tester.renderObject(find.byType(CustomSingleChildLayout)); expect(box.size, equals(const Size(150.0, 240.0))); }); }