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