1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/material.dart';
6
7/// Flutter code sample for [CustomMultiChildLayout].
8
9void main() => runApp(const CustomMultiChildLayoutApp());
10
11class CustomMultiChildLayoutApp extends StatelessWidget {
12 const CustomMultiChildLayoutApp({super.key});
13
14 @override
15 Widget build(BuildContext context) {
16 return const MaterialApp(
17 home: Directionality(
18 // TRY THIS: Try changing the direction here and hot-reloading to
19 // see the layout change.
20 textDirection: TextDirection.ltr,
21 child: Scaffold(body: CustomMultiChildLayoutExample()),
22 ),
23 );
24 }
25}
26
27/// Lays out the children in a cascade, where the top corner of the next child
28/// is a little above (`overlap`) the lower end corner of the previous child.
29///
30/// Will relayout if the text direction changes.
31class _CascadeLayoutDelegate extends MultiChildLayoutDelegate {
32 _CascadeLayoutDelegate({
33 required this.colors,
34 required this.overlap,
35 required this.textDirection,
36 });
37
38 final Map<String, Color> colors;
39 final double overlap;
40 final TextDirection textDirection;
41
42 // Perform layout will be called when re-layout is needed.
43 @override
44 void performLayout(Size size) {
45 final double columnWidth = size.width / colors.length;
46 Offset childPosition = Offset.zero;
47 switch (textDirection) {
48 case TextDirection.rtl:
49 childPosition += Offset(size.width, 0);
50 case TextDirection.ltr:
51 break;
52 }
53 for (final String color in colors.keys) {
54 // layoutChild must be called exactly once for each child.
55 final Size currentSize = layoutChild(
56 color,
57 BoxConstraints(maxHeight: size.height, maxWidth: columnWidth),
58 );
59 // positionChild must be called to change the position of a child from
60 // what it was in the previous layout. Each child starts at (0, 0) for the
61 // first layout.
62 switch (textDirection) {
63 case TextDirection.rtl:
64 positionChild(color, childPosition - Offset(currentSize.width, 0));
65 childPosition += Offset(-currentSize.width, currentSize.height - overlap);
66 case TextDirection.ltr:
67 positionChild(color, childPosition);
68 childPosition += Offset(currentSize.width, currentSize.height - overlap);
69 }
70 }
71 }
72
73 // shouldRelayout is called to see if the delegate has changed and requires a
74 // layout to occur. Should only return true if the delegate state itself
75 // changes: changes in the CustomMultiChildLayout attributes will
76 // automatically cause a relayout, like any other widget.
77 @override
78 bool shouldRelayout(_CascadeLayoutDelegate oldDelegate) {
79 return oldDelegate.textDirection != textDirection || oldDelegate.overlap != overlap;
80 }
81}
82
83class CustomMultiChildLayoutExample extends StatelessWidget {
84 const CustomMultiChildLayoutExample({super.key});
85
86 static const Map<String, Color> _colors = <String, Color>{
87 'Red': Colors.red,
88 'Green': Colors.green,
89 'Blue': Colors.blue,
90 'Cyan': Colors.cyan,
91 };
92
93 @override
94 Widget build(BuildContext context) {
95 return CustomMultiChildLayout(
96 delegate: _CascadeLayoutDelegate(
97 colors: _colors,
98 overlap: 30.0,
99 textDirection: Directionality.of(context),
100 ),
101 children: <Widget>[
102 // Create all of the colored boxes in the colors map.
103 for (final MapEntry<String, Color> entry in _colors.entries)
104 // The "id" can be any Object, not just a String.
105 LayoutId(
106 id: entry.key,
107 child: Container(
108 color: entry.value,
109 width: 100.0,
110 height: 100.0,
111 alignment: Alignment.center,
112 child: Text(entry.key),
113 ),
114 ),
115 ],
116 );
117 }
118}
119

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com