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/foundation.dart';
6
7import 'basic.dart';
8import 'framework.dart';
9
10class _PlaceholderPainter extends CustomPainter {
11 const _PlaceholderPainter({
12 required this.color,
13 required this.strokeWidth,
14 });
15
16 final Color color;
17 final double strokeWidth;
18
19 @override
20 void paint(Canvas canvas, Size size) {
21 final Paint paint = Paint()
22 ..color = color
23 ..style = PaintingStyle.stroke
24 ..strokeWidth = strokeWidth;
25 final Rect rect = Offset.zero & size;
26 final Path path = Path()
27 ..addRect(rect)
28 ..addPolygon(<Offset>[rect.topRight, rect.bottomLeft], false)
29 ..addPolygon(<Offset>[rect.topLeft, rect.bottomRight], false);
30 canvas.drawPath(path, paint);
31 }
32
33 @override
34 bool shouldRepaint(_PlaceholderPainter oldPainter) {
35 return oldPainter.color != color
36 || oldPainter.strokeWidth != strokeWidth;
37 }
38
39 @override
40 bool hitTest(Offset position) => false;
41}
42
43/// A widget that draws a box that represents where other widgets will one day
44/// be added.
45///
46/// This widget is useful during development to indicate that the interface is
47/// not yet complete.
48///
49/// By default, the placeholder is sized to fit its container. If the
50/// placeholder is in an unbounded space, it will size itself according to the
51/// given [fallbackWidth] and [fallbackHeight].
52///
53/// {@youtube 560 315 https://www.youtube.com/watch?v=LPe56fezmoo}
54class Placeholder extends StatelessWidget {
55 /// Creates a widget which draws a box.
56 const Placeholder({
57 super.key,
58 this.color = const Color(0xFF455A64), // Blue Grey 700
59 this.strokeWidth = 2.0,
60 this.fallbackWidth = 400.0,
61 this.fallbackHeight = 400.0,
62 this.child
63 });
64
65 /// The color to draw the placeholder box.
66 final Color color;
67
68 /// The width of the lines in the placeholder box.
69 final double strokeWidth;
70
71 /// The width to use when the placeholder is in a situation with an unbounded
72 /// width.
73 ///
74 /// See also:
75 ///
76 /// * [fallbackHeight], the same but vertically.
77 final double fallbackWidth;
78
79 /// The height to use when the placeholder is in a situation with an unbounded
80 /// height.
81 ///
82 /// See also:
83 ///
84 /// * [fallbackWidth], the same but horizontally.
85 final double fallbackHeight;
86
87 /// The [child] contained by the placeholder box.
88 ///
89 /// Defaults to null.
90 final Widget? child;
91 @override
92 Widget build(BuildContext context) {
93 return LimitedBox(
94 maxWidth: fallbackWidth,
95 maxHeight: fallbackHeight,
96 child: CustomPaint(
97 size: Size.infinite,
98 painter: _PlaceholderPainter(
99 color: color,
100 strokeWidth: strokeWidth,
101 ),
102 child: child,
103 ),
104 );
105 }
106
107 @override
108 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
109 super.debugFillProperties(properties);
110 properties.add(ColorProperty('color', color, defaultValue: const Color(0xFF455A64)));
111 properties.add(DoubleProperty('strokeWidth', strokeWidth, defaultValue: 2.0));
112 properties.add(DoubleProperty('fallbackWidth', fallbackWidth, defaultValue: 400.0));
113 properties.add(DoubleProperty('fallbackHeight', fallbackHeight, defaultValue: 400.0));
114 properties.add(DiagnosticsProperty<Widget>('child', child, defaultValue: null));
115 }
116}
117