-
Notifications
You must be signed in to change notification settings - Fork 30.2k
Expand file tree
/
Copy pathframework.dart
More file actions
7455 lines (7037 loc) · 300 KB
/
framework.dart
File metadata and controls
7455 lines (7037 loc) · 300 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// 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.
/// @docImport 'dart:ui';
///
/// @docImport 'package:flutter/animation.dart';
/// @docImport 'package:flutter/material.dart';
/// @docImport 'package:flutter/widgets.dart';
/// @docImport 'package:flutter_test/flutter_test.dart';
library;
import 'dart:async';
import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'binding.dart';
import 'debug.dart';
import 'focus_manager.dart';
import 'inherited_model.dart';
import 'notification_listener.dart';
import 'widget_inspector.dart';
export 'package:flutter/foundation.dart'
show
factory,
immutable,
mustCallSuper,
optionalTypeArgs,
protected,
required,
visibleForTesting;
export 'package:flutter/foundation.dart'
show ErrorDescription, ErrorHint, ErrorSummary, FlutterError, debugPrint, debugPrintStack;
export 'package:flutter/foundation.dart' show DiagnosticLevel, DiagnosticsNode;
export 'package:flutter/foundation.dart' show Key, LocalKey, ValueKey;
export 'package:flutter/foundation.dart' show ValueChanged, ValueGetter, ValueSetter, VoidCallback;
export 'package:flutter/rendering.dart'
show RenderBox, RenderObject, debugDumpLayerTree, debugDumpRenderTree;
// Examples can assume:
// late BuildContext context;
// void setState(VoidCallback fn) { }
// abstract class RenderFrogJar extends RenderObject { }
// abstract class FrogJar extends RenderObjectWidget { const FrogJar({super.key}); }
// abstract class FrogJarParentData extends ParentData { late Size size; }
// abstract class SomeWidget extends StatefulWidget { const SomeWidget({super.key}); }
// typedef ChildWidget = Placeholder;
// class _SomeWidgetState extends State<SomeWidget> { @override Widget build(BuildContext context) => widget; }
// abstract class RenderFoo extends RenderObject { }
// abstract class Foo extends RenderObjectWidget { const Foo({super.key}); }
// abstract class StatefulWidgetX { const StatefulWidgetX({this.key}); final Key? key; Widget build(BuildContext context, State state); }
// class SpecialWidget extends StatelessWidget { const SpecialWidget({ super.key, this.handler }); final VoidCallback? handler; @override Widget build(BuildContext context) => this; }
// late Object? _myState, newValue;
// int _counter = 0;
// Future<Directory> getApplicationDocumentsDirectory() async => Directory('');
// late AnimationController animation;
class _DebugOnly {
const _DebugOnly();
}
/// An annotation used by test_analysis package to verify patterns are followed
/// that allow for tree-shaking of both fields and their initializers. This
/// annotation has no impact on code by itself, but indicates the following pattern
/// should be followed for a given field:
///
/// ```dart
/// class Bar {
/// final Object? bar = kDebugMode ? Object() : null;
/// }
/// ```
const _DebugOnly _debugOnly = _DebugOnly();
// KEYS
/// A key that takes its identity from the object used as its value.
///
/// Used to tie the identity of a widget to the identity of an object used to
/// generate that widget.
///
/// See also:
///
/// * [Key], the base class for all keys.
/// * The discussion at [Widget.key] for more information about how widgets use
/// keys.
class ObjectKey extends LocalKey {
/// Creates a key that uses [identical] on [value] for its [operator==].
const ObjectKey(this.value);
/// The object whose identity is used by this key's [operator==].
final Object? value;
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) {
return false;
}
return other is ObjectKey && identical(other.value, value);
}
@override
int get hashCode => Object.hash(runtimeType, identityHashCode(value));
@override
String toString() {
if (runtimeType == ObjectKey) {
return '[${describeIdentity(value)}]';
}
return '[${objectRuntimeType(this, 'ObjectKey')} ${describeIdentity(value)}]';
}
}
/// A key that is unique across the entire app.
///
/// Global keys uniquely identify elements. Global keys provide access to other
/// objects that are associated with those elements, such as [BuildContext].
/// For [StatefulWidget]s, global keys also provide access to [State].
///
/// Widgets that have global keys reparent their subtrees when they are moved
/// from one location in the tree to another location in the tree. In order to
/// reparent its subtree, a widget must arrive at its new location in the tree
/// in the same animation frame in which it was removed from its old location in
/// the tree.
///
/// Reparenting an [Element] using a global key is relatively expensive, as
/// this operation will trigger a call to [State.deactivate] on the associated
/// [State] and all of its descendants; then force all widgets that depends
/// on an [InheritedWidget] to rebuild.
///
/// If you don't need any of the features listed above, consider using a [Key],
/// [ValueKey], [ObjectKey], or [UniqueKey] instead.
///
/// You cannot simultaneously include two widgets in the tree with the same
/// global key. Attempting to do so will assert at runtime.
///
/// ## Pitfalls
///
/// GlobalKeys should not be re-created on every build. They should usually be
/// long-lived objects owned by a [State] object, for example.
///
/// Creating a new GlobalKey on every build will throw away the state of the
/// subtree associated with the old key and create a new fresh subtree for the
/// new key. Besides harming performance, this can also cause unexpected
/// behavior in widgets in the subtree. For example, a [GestureDetector] in the
/// subtree will be unable to track ongoing gestures since it will be recreated
/// on each build.
///
/// Instead, a good practice is to let a State object own the GlobalKey, and
/// instantiate it outside the build method, such as in [State.initState].
///
/// See also:
///
/// * The discussion at [Widget.key] for more information about how widgets use
/// keys.
@optionalTypeArgs
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
/// Creates a [LabeledGlobalKey], which is a [GlobalKey] with a label used for
/// debugging.
///
/// The label is purely for debugging and not used for comparing the identity
/// of the key.
factory GlobalKey({String? debugLabel}) => LabeledGlobalKey<T>(debugLabel);
/// Creates a global key without a label.
///
/// Used by subclasses because the factory constructor shadows the implicit
/// constructor.
const GlobalKey.constructor() : super.empty();
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
/// The build context in which the widget with this key builds.
///
/// The current context is null if there is no widget in the tree that matches
/// this global key.
BuildContext? get currentContext => _currentElement;
/// The widget in the tree that currently has this global key.
///
/// The current widget is null if there is no widget in the tree that matches
/// this global key.
Widget? get currentWidget => _currentElement?.widget;
/// The [State] for the widget in the tree that currently has this global key.
///
/// The current state is null if (1) there is no widget in the tree that
/// matches this global key, (2) that widget is not a [StatefulWidget], or the
/// associated [State] object is not a subtype of `T`.
T? get currentState => switch (_currentElement) {
StatefulElement(:final T state) => state,
_ => null,
};
}
/// A global key with a debugging label.
///
/// The debug label is useful for documentation and for debugging. The label
/// does not affect the key's identity.
@optionalTypeArgs
class LabeledGlobalKey<T extends State<StatefulWidget>> extends GlobalKey<T> {
/// Creates a global key with a debugging label.
///
/// The label does not affect the key's identity.
// ignore: prefer_const_constructors_in_immutables , never use const for this class
LabeledGlobalKey(this._debugLabel) : super.constructor();
final String? _debugLabel;
@override
String toString() {
final label = _debugLabel != null ? ' $_debugLabel' : '';
if (runtimeType == LabeledGlobalKey) {
return '[GlobalKey#${shortHash(this)}$label]';
}
return '[${describeIdentity(this)}$label]';
}
}
/// A global key that takes its identity from the object used as its value.
///
/// Used to tie the identity of a widget to the identity of an object used to
/// generate that widget.
///
/// Any [GlobalObjectKey] created for the same object will match.
///
/// If the object is not private, then it is possible that collisions will occur
/// where independent widgets will reuse the same object as their
/// [GlobalObjectKey] value in a different part of the tree, leading to a global
/// key conflict. To avoid this problem, create a private [GlobalObjectKey]
/// subclass, as in:
///
/// ```dart
/// class _MyKey extends GlobalObjectKey {
/// const _MyKey(super.value);
/// }
/// ```
///
/// Since the [runtimeType] of the key is part of its identity, this will
/// prevent clashes with other [GlobalObjectKey]s even if they have the same
/// value.
@optionalTypeArgs
class GlobalObjectKey<T extends State<StatefulWidget>> extends GlobalKey<T> {
/// Creates a global key that uses [identical] on [value] for its [operator==].
const GlobalObjectKey(this.value) : super.constructor();
/// The object whose identity is used by this key's [operator==].
final Object value;
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType) {
return false;
}
return other is GlobalObjectKey<T> && identical(other.value, value);
}
@override
int get hashCode => identityHashCode(value);
@override
String toString() {
String selfType = objectRuntimeType(this, 'GlobalObjectKey');
// The runtimeType string of a GlobalObjectKey() returns 'GlobalObjectKey<State<StatefulWidget>>'
// because GlobalObjectKey is instantiated to its bounds. To avoid cluttering the output
// we remove the suffix.
const suffix = '<State<StatefulWidget>>';
if (selfType.endsWith(suffix)) {
selfType = selfType.substring(0, selfType.length - suffix.length);
}
return '[$selfType ${describeIdentity(value)}]';
}
}
/// Describes the configuration for an [Element].
///
/// Widgets are the central class hierarchy in the Flutter framework. A widget
/// is an immutable description of part of a user interface. Widgets can be
/// inflated into elements, which manage the underlying render tree.
///
/// Widgets themselves have no mutable state (all their fields must be final).
/// If you wish to associate mutable state with a widget, consider using a
/// [StatefulWidget], which creates a [State] object (via
/// [StatefulWidget.createState]) whenever it is inflated into an element and
/// incorporated into the tree.
///
/// A given widget can be included in the tree zero or more times. In particular
/// a given widget can be placed in the tree multiple times. Each time a widget
/// is placed in the tree, it is inflated into an [Element], which means a
/// widget that is incorporated into the tree multiple times will be inflated
/// multiple times.
///
/// The [key] property controls how one widget replaces another widget in the
/// tree. If the [runtimeType] and [key] properties of the two widgets are
/// [operator==], respectively, then the new widget replaces the old widget by
/// updating the underlying element (i.e., by calling [Element.update] with the
/// new widget). Otherwise, the old element is removed from the tree, the new
/// widget is inflated into an element, and the new element is inserted into the
/// tree.
///
/// See also:
///
/// * [StatefulWidget] and [State], for widgets that can build differently
/// several times over their lifetime.
/// * [InheritedWidget], for widgets that introduce ambient state that can
/// be read by descendant widgets.
/// * [StatelessWidget], for widgets that always build the same way given a
/// particular configuration and ambient state.
@immutable
abstract class Widget extends DiagnosticableTree {
/// Initializes [key] for subclasses.
const Widget({this.key});
/// Controls how one widget replaces another widget in the tree.
///
/// If the [runtimeType] and [key] properties of the two widgets are
/// [operator==], respectively, then the new widget replaces the old widget by
/// updating the underlying element (i.e., by calling [Element.update] with the
/// new widget). Otherwise, the old element is removed from the tree, the new
/// widget is inflated into an element, and the new element is inserted into the
/// tree.
///
/// In addition, using a [GlobalKey] as the widget's [key] allows the element
/// to be moved around the tree (changing parent) without losing state. When a
/// new widget is found (its key and type do not match a previous widget in
/// the same location), but there was a widget with that same global key
/// elsewhere in the tree in the previous frame, then that widget's element is
/// moved to the new location.
///
/// Generally, a widget that is the only child of another widget does not need
/// an explicit key.
///
/// See also:
///
/// * The discussions at [Key] and [GlobalKey].
final Key? key;
/// Inflates this configuration to a concrete instance.
///
/// A given widget can be included in the tree zero or more times. In particular
/// a given widget can be placed in the tree multiple times. Each time a widget
/// is placed in the tree, it is inflated into an [Element], which means a
/// widget that is incorporated into the tree multiple times will be inflated
/// multiple times.
@protected
@factory
Element createElement();
/// A short, textual description of this widget.
@override
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
@override
@nonVirtual
bool operator ==(Object other) => super == other;
@override
@nonVirtual
int get hashCode => super.hashCode;
/// Whether the `newWidget` can be used to update an [Element] that currently
/// has the `oldWidget` as its configuration.
///
/// An element that uses a given widget as its configuration can be updated to
/// use another widget as its configuration if, and only if, the two widgets
/// have [runtimeType] and [key] properties that are [operator==].
///
/// If the widgets have no key (their key is null), then they are considered a
/// match if they have the same type, even if their children are completely
/// different.
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key;
}
// Return a numeric encoding of the specific `Widget` concrete subtype.
// This is used in `Element.updateChild` to determine if a hot reload modified the
// superclass of a mounted element's configuration. The encoding of each `Widget`
// must match the corresponding `Element` encoding in `Element._debugConcreteSubtype`.
static int _debugConcreteSubtype(Widget widget) {
return widget is StatefulWidget
? 1
: widget is StatelessWidget
? 2
: 0;
}
}
/// A widget that does not require mutable state.
///
/// A stateless widget is a widget that describes part of the user interface by
/// building a constellation of other widgets that describe the user interface
/// more concretely. The building process continues recursively until the
/// description of the user interface is fully concrete (e.g., consists
/// entirely of [RenderObjectWidget]s, which describe concrete [RenderObject]s).
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=wE7khGHVkYY}
///
/// Stateless widget are useful when the part of the user interface you are
/// describing does not depend on anything other than the configuration
/// information in the object itself and the [BuildContext] in which the widget
/// is inflated. For compositions that can change dynamically, e.g. due to
/// having an internal clock-driven state, or depending on some system state,
/// consider using [StatefulWidget].
///
/// ## Performance considerations
///
/// The [build] method of a stateless widget is typically only called in three
/// situations: the first time the widget is inserted in the tree, when the
/// widget's parent changes its configuration (see [Element.rebuild]), and when
/// an [InheritedWidget] it depends on changes.
///
/// If a widget's parent will regularly change the widget's configuration, or if
/// it depends on inherited widgets that frequently change, then it is important
/// to optimize the performance of the [build] method to maintain a fluid
/// rendering performance.
///
/// There are several techniques one can use to minimize the impact of
/// rebuilding a stateless widget:
///
/// * Minimize the number of nodes transitively created by the build method and
/// any widgets it creates. For example, instead of an elaborate arrangement
/// of [Row]s, [Column]s, [Padding]s, and [SizedBox]es to position a single
/// child in a particularly fancy manner, consider using just an [Align] or a
/// [CustomSingleChildLayout]. Instead of an intricate layering of multiple
/// [Container]s and with [Decoration]s to draw just the right graphical
/// effect, consider a single [CustomPaint] widget.
///
/// * Use `const` widgets where possible, and provide a `const` constructor for
/// the widget so that users of the widget can also do so.
///
/// * Consider refactoring the stateless widget into a stateful widget so that
/// it can use some of the techniques described at [StatefulWidget], such as
/// caching common parts of subtrees and using [GlobalKey]s when changing the
/// tree structure.
///
/// * If the widget is likely to get rebuilt frequently due to the use of
/// [InheritedWidget]s, consider refactoring the stateless widget into
/// multiple widgets, with the parts of the tree that change being pushed to
/// the leaves. For example instead of building a tree with four widgets, the
/// inner-most widget depending on the [Theme], consider factoring out the
/// part of the build function that builds the inner-most widget into its own
/// widget, so that only the inner-most widget needs to be rebuilt when the
/// theme changes.
/// {@template flutter.flutter.widgets.framework.prefer_const_over_helper}
/// * When trying to create a reusable piece of UI, prefer using a widget
/// rather than a helper method. For example, if there was a function used to
/// build a widget, a [State.setState] call would require Flutter to entirely
/// rebuild the returned wrapping widget. If a [Widget] was used instead,
/// Flutter would be able to efficiently re-render only those parts that
/// really need to be updated. Even better, if the created widget is `const`,
/// Flutter would short-circuit most of the rebuild work.
/// {@endtemplate}
///
/// This video gives more explanations on why `const` constructors are important
/// and why a [Widget] is better than a helper method.
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=IOyq-eTRhvo}
///
/// {@tool snippet}
///
/// The following is a skeleton of a stateless widget subclass called `GreenFrog`.
///
/// Normally, widgets have more constructor arguments, each of which corresponds
/// to a `final` property.
///
/// ```dart
/// class GreenFrog extends StatelessWidget {
/// const GreenFrog({ super.key });
///
/// @override
/// Widget build(BuildContext context) {
/// return Container(color: const Color(0xFF2DBD3A));
/// }
/// }
/// ```
/// {@end-tool}
///
/// {@tool snippet}
///
/// This next example shows the more generic widget `Frog` which can be given
/// a color and a child:
///
/// ```dart
/// class Frog extends StatelessWidget {
/// const Frog({
/// super.key,
/// this.color = const Color(0xFF2DBD3A),
/// this.child,
/// });
///
/// final Color color;
/// final Widget? child;
///
/// @override
/// Widget build(BuildContext context) {
/// return ColoredBox(color: color, child: child);
/// }
/// }
/// ```
/// {@end-tool}
///
/// By convention, widget constructors only use named arguments. Also by
/// convention, the first argument is [key], and the last argument is `child`,
/// `children`, or the equivalent.
///
/// See also:
///
/// * [StatefulWidget] and [State], for widgets that can build differently
/// several times over their lifetime.
/// * [InheritedWidget], for widgets that introduce ambient state that can
/// be read by descendant widgets.
abstract class StatelessWidget extends Widget {
/// Initializes [key] for subclasses.
const StatelessWidget({super.key});
/// Creates a [StatelessElement] to manage this widget's location in the tree.
///
/// It is uncommon for subclasses to override this method.
@override
StatelessElement createElement() => StatelessElement(this);
/// Describes the part of the user interface represented by this widget.
///
/// The framework calls this method when this widget is inserted into the tree
/// in a given [BuildContext] and when the dependencies of this widget change
/// (e.g., an [InheritedWidget] referenced by this widget changes). This
/// method can potentially be called in every frame and should not have any side
/// effects beyond building a widget.
///
/// The framework replaces the subtree below this widget with the widget
/// returned by this method, either by updating the existing subtree or by
/// removing the subtree and inflating a new subtree, depending on whether the
/// widget returned by this method can update the root of the existing
/// subtree, as determined by calling [Widget.canUpdate].
///
/// Typically implementations return a newly created constellation of widgets
/// that are configured with information from this widget's constructor and
/// from the given [BuildContext].
///
/// The given [BuildContext] contains information about the location in the
/// tree at which this widget is being built. For example, the context
/// provides the set of inherited widgets for this location in the tree. A
/// given widget might be built with multiple different [BuildContext]
/// arguments over time if the widget is moved around the tree or if the
/// widget is inserted into the tree in multiple places at once.
///
/// The implementation of this method must only depend on:
///
/// * the fields of the widget, which themselves must not change over time,
/// and
/// * any ambient state obtained from the `context` using
/// [BuildContext.dependOnInheritedWidgetOfExactType].
///
/// If a widget's [build] method is to depend on anything else, use a
/// [StatefulWidget] instead.
///
/// See also:
///
/// * [StatelessWidget], which contains the discussion on performance considerations.
@protected
Widget build(BuildContext context);
}
/// A widget that has mutable state.
///
/// State is information that (1) can be read synchronously when the widget is
/// built and (2) might change during the lifetime of the widget. It is the
/// responsibility of the widget implementer to ensure that the [State] is
/// promptly notified when such state changes, using [State.setState].
///
/// A stateful widget is a widget that describes part of the user interface by
/// building a constellation of other widgets that describe the user interface
/// more concretely. The building process continues recursively until the
/// description of the user interface is fully concrete (e.g., consists
/// entirely of [RenderObjectWidget]s, which describe concrete [RenderObject]s).
///
/// Stateful widgets are useful when the part of the user interface you are
/// describing can change dynamically, e.g. due to having an internal
/// clock-driven state, or depending on some system state. For compositions that
/// depend only on the configuration information in the object itself and the
/// [BuildContext] in which the widget is inflated, consider using
/// [StatelessWidget].
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=AqCMFXEmf3w}
///
/// [StatefulWidget] instances themselves are immutable and store their mutable
/// state either in separate [State] objects that are created by the
/// [createState] method, or in objects to which that [State] subscribes, for
/// example [Stream] or [ChangeNotifier] objects, to which references are stored
/// in final fields on the [StatefulWidget] itself.
///
/// The framework calls [createState] whenever it inflates a
/// [StatefulWidget], which means that multiple [State] objects might be
/// associated with the same [StatefulWidget] if that widget has been inserted
/// into the tree in multiple places. Similarly, if a [StatefulWidget] is
/// removed from the tree and later inserted in to the tree again, the framework
/// will call [createState] again to create a fresh [State] object, simplifying
/// the lifecycle of [State] objects.
///
/// A [StatefulWidget] keeps the same [State] object when moving from one
/// location in the tree to another if its creator used a [GlobalKey] for its
/// [key]. Because a widget with a [GlobalKey] can be used in at most one
/// location in the tree, a widget that uses a [GlobalKey] has at most one
/// associated element. The framework takes advantage of this property when
/// moving a widget with a global key from one location in the tree to another
/// by grafting the (unique) subtree associated with that widget from the old
/// location to the new location (instead of recreating the subtree at the new
/// location). The [State] objects associated with [StatefulWidget] are grafted
/// along with the rest of the subtree, which means the [State] object is reused
/// (instead of being recreated) in the new location. However, in order to be
/// eligible for grafting, the widget must be inserted into the new location in
/// the same animation frame in which it was removed from the old location.
///
/// ## Performance considerations
///
/// There are two primary categories of [StatefulWidget]s.
///
/// The first is one which allocates resources in [State.initState] and disposes
/// of them in [State.dispose], but which does not depend on [InheritedWidget]s
/// or call [State.setState]. Such widgets are commonly used at the root of an
/// application or page, and communicate with subwidgets via [ChangeNotifier]s,
/// [Stream]s, or other such objects. Stateful widgets following such a pattern
/// are relatively cheap (in terms of CPU and GPU cycles), because they are
/// built once then never update. They can, therefore, have somewhat complicated
/// and deep build methods.
///
/// The second category is widgets that use [State.setState] or depend on
/// [InheritedWidget]s. These will typically rebuild many times during the
/// application's lifetime, and it is therefore important to minimize the impact
/// of rebuilding such a widget. (They may also use [State.initState] or
/// [State.didChangeDependencies] and allocate resources, but the important part
/// is that they rebuild.)
///
/// There are several techniques one can use to minimize the impact of
/// rebuilding a stateful widget:
///
/// * Push the state to the leaves. For example, if your page has a ticking
/// clock, rather than putting the state at the top of the page and
/// rebuilding the entire page each time the clock ticks, create a dedicated
/// clock widget that only updates itself.
///
/// * Minimize the number of nodes transitively created by the build method and
/// any widgets it creates. Ideally, a stateful widget would only create a
/// single widget, and that widget would be a [RenderObjectWidget].
/// (Obviously this isn't always practical, but the closer a widget gets to
/// this ideal, the more efficient it will be.)
///
/// * If a subtree does not change, cache the widget that represents that
/// subtree and re-use it each time it can be used. To do this, assign
/// a widget to a `final` state variable and re-use it in the build method. It
/// is massively more efficient for a widget to be re-used than for a new (but
/// identically-configured) widget to be created. Another caching strategy
/// consists in extracting the mutable part of the widget into a [StatefulWidget]
/// which accepts a child parameter.
///
/// * Use `const` widgets where possible. (This is equivalent to caching a
/// widget and re-using it.)
///
/// * Avoid changing the depth of any created subtrees or changing the type of
/// any widgets in the subtree. For example, rather than returning either the
/// child or the child wrapped in an [IgnorePointer], always wrap the child
/// widget in an [IgnorePointer] and control the [IgnorePointer.ignoring]
/// property. This is because changing the depth of the subtree requires
/// rebuilding, laying out, and painting the entire subtree, whereas just
/// changing the property will require the least possible change to the
/// render tree (in the case of [IgnorePointer], for example, no layout or
/// repaint is necessary at all).
///
/// * If the depth must be changed for some reason, consider wrapping the
/// common parts of the subtrees in widgets that have a [GlobalKey] that
/// remains consistent for the life of the stateful widget. (The
/// [KeyedSubtree] widget may be useful for this purpose if no other widget
/// can conveniently be assigned the key.)
///
/// {@macro flutter.flutter.widgets.framework.prefer_const_over_helper}
///
/// This video gives more explanations on why `const` constructors are important
/// and why a [Widget] is better than a helper method.
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=IOyq-eTRhvo}
///
/// For more details on the mechanics of rebuilding a widget, see
/// the discussion at [Element.rebuild].
///
/// {@tool snippet}
///
/// This is a skeleton of a stateful widget subclass called `YellowBird`.
///
/// In this example, the [State] has no actual state. State is normally
/// represented as private member fields. Also, normally widgets have more
/// constructor arguments, each of which corresponds to a `final` property.
///
/// ```dart
/// class YellowBird extends StatefulWidget {
/// const YellowBird({ super.key });
///
/// @override
/// State<YellowBird> createState() => _YellowBirdState();
/// }
///
/// class _YellowBirdState extends State<YellowBird> {
/// @override
/// Widget build(BuildContext context) {
/// return Container(color: const Color(0xFFFFE306));
/// }
/// }
/// ```
/// {@end-tool}
/// {@tool snippet}
///
/// This example shows the more generic widget `Bird` which can be given a
/// color and a child, and which has some internal state with a method that
/// can be called to mutate it:
///
/// ```dart
/// class Bird extends StatefulWidget {
/// const Bird({
/// super.key,
/// this.color = const Color(0xFFFFE306),
/// this.child,
/// });
///
/// final Color color;
/// final Widget? child;
///
/// @override
/// State<Bird> createState() => _BirdState();
/// }
///
/// class _BirdState extends State<Bird> {
/// double _size = 1.0;
///
/// void grow() {
/// setState(() { _size += 0.1; });
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return Container(
/// color: widget.color,
/// transform: Matrix4.diagonal3Values(_size, _size, 1.0),
/// child: widget.child,
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// By convention, widget constructors only use named arguments. Also by
/// convention, the first argument is [key], and the last argument is `child`,
/// `children`, or the equivalent.
///
/// See also:
///
/// * [State], where the logic behind a [StatefulWidget] is hosted.
/// * [StatelessWidget], for widgets that always build the same way given a
/// particular configuration and ambient state.
/// * [InheritedWidget], for widgets that introduce ambient state that can
/// be read by descendant widgets.
abstract class StatefulWidget extends Widget {
/// Initializes [key] for subclasses.
const StatefulWidget({super.key});
/// Creates a [StatefulElement] to manage this widget's location in the tree.
///
/// It is uncommon for subclasses to override this method.
@override
StatefulElement createElement() => StatefulElement(this);
/// Creates the mutable state for this widget at a given location in the tree.
///
/// Subclasses should override this method to return a newly created
/// instance of their associated [State] subclass:
///
/// ```dart
/// @override
/// State<SomeWidget> createState() => _SomeWidgetState();
/// ```
///
/// The framework can call this method multiple times over the lifetime of
/// a [StatefulWidget]. For example, if the widget is inserted into the tree
/// in multiple locations, the framework will create a separate [State] object
/// for each location. Similarly, if the widget is removed from the tree and
/// later inserted into the tree again, the framework will call [createState]
/// again to create a fresh [State] object, simplifying the lifecycle of
/// [State] objects.
@protected
@factory
State createState();
}
/// Tracks the lifecycle of [State] objects when asserts are enabled.
enum _StateLifecycle {
/// The [State] object has been created. [State.initState] is called at this
/// time.
created,
/// The [State.initState] method has been called but the [State] object is
/// not yet ready to build. [State.didChangeDependencies] is called at this time.
initialized,
/// The [State] object is ready to build and [State.dispose] has not yet been
/// called.
ready,
/// The [State.dispose] method has been called and the [State] object is
/// no longer able to build.
defunct,
}
/// The signature of [State.setState] functions.
typedef StateSetter = void Function(VoidCallback fn);
/// The logic and internal state for a [StatefulWidget].
///
/// State is information that (1) can be read synchronously when the widget is
/// built and (2) might change during the lifetime of the widget. It is the
/// responsibility of the widget implementer to ensure that the [State] is
/// promptly notified when such state changes, using [State.setState].
///
/// [State] objects are created by the framework by calling the
/// [StatefulWidget.createState] method when inflating a [StatefulWidget] to
/// insert it into the tree. Because a given [StatefulWidget] instance can be
/// inflated multiple times (e.g., the widget is incorporated into the tree in
/// multiple places at once), there might be more than one [State] object
/// associated with a given [StatefulWidget] instance. Similarly, if a
/// [StatefulWidget] is removed from the tree and later inserted in to the tree
/// again, the framework will call [StatefulWidget.createState] again to create
/// a fresh [State] object, simplifying the lifecycle of [State] objects.
///
/// [State] objects have the following lifecycle:
///
/// * The framework creates a [State] object by calling
/// [StatefulWidget.createState].
/// * The newly created [State] object is associated with a [BuildContext].
/// This association is permanent: the [State] object will never change its
/// [BuildContext]. However, the [BuildContext] itself can be moved around
/// the tree along with its subtree. At this point, the [State] object is
/// considered [mounted].
/// * The framework calls [initState]. Subclasses of [State] should override
/// [initState] to perform one-time initialization that depends on the
/// [BuildContext] or the widget, which are available as the [context] and
/// [widget] properties, respectively, when the [initState] method is
/// called.
/// * The framework calls [didChangeDependencies]. Subclasses of [State] should
/// override [didChangeDependencies] to perform initialization involving
/// [InheritedWidget]s. If [BuildContext.dependOnInheritedWidgetOfExactType] is
/// called, the [didChangeDependencies] method will be called again if the
/// inherited widgets subsequently change or if the widget moves in the tree.
/// * At this point, the [State] object is fully initialized and the framework
/// might call its [build] method any number of times to obtain a
/// description of the user interface for this subtree. [State] objects can
/// spontaneously request to rebuild their subtree by calling their
/// [setState] method, which indicates that some of their internal state
/// has changed in a way that might impact the user interface in this
/// subtree.
/// * During this time, a parent widget might rebuild and request that this
/// location in the tree update to display a new widget with the same
/// [runtimeType] and [Widget.key]. When this happens, the framework will
/// update the [widget] property to refer to the new widget and then call the
/// [didUpdateWidget] method with the previous widget as an argument. [State]
/// objects should override [didUpdateWidget] to respond to changes in their
/// associated widget (e.g., to start implicit animations). The framework
/// always calls [build] after calling [didUpdateWidget], which means any
/// calls to [setState] in [didUpdateWidget] are redundant. (See also the
/// discussion at [Element.rebuild].)
/// * During development, if a hot reload occurs (whether initiated from the
/// command line `flutter` tool by pressing `r`, or from an IDE), the
/// [reassemble] method is called. This provides an opportunity to
/// reinitialize any data that was prepared in the [initState] method.
/// * If the subtree containing the [State] object is removed from the tree
/// (e.g., because the parent built a widget with a different [runtimeType]
/// or [Widget.key]), the framework calls the [deactivate] method. Subclasses
/// should override this method to clean up any links between this object
/// and other elements in the tree (e.g. if you have provided an ancestor
/// with a pointer to a descendant's [RenderObject]).
/// * At this point, the framework might reinsert this subtree into another
/// part of the tree. If that happens, the framework will ensure that it
/// calls [build] to give the [State] object a chance to adapt to its new
/// location in the tree. If the framework does reinsert this subtree, it
/// will do so before the end of the animation frame in which the subtree was
/// removed from the tree. For this reason, [State] objects can defer
/// releasing most resources until the framework calls their [dispose]
/// method.
/// * If the framework does not reinsert this subtree by the end of the current
/// animation frame, the framework will call [dispose], which indicates that
/// this [State] object will never build again. Subclasses should override
/// this method to release any resources retained by this object (e.g.,
/// stop any active animations).
/// * After the framework calls [dispose], the [State] object is considered
/// unmounted and the [mounted] property is false. It is an error to call
/// [setState] at this point. This stage of the lifecycle is terminal: there
/// is no way to remount a [State] object that has been disposed.
///
/// See also:
///
/// * [StatefulWidget], where the current configuration of a [State] is hosted,
/// and whose documentation has sample code for [State].
/// * [StatelessWidget], for widgets that always build the same way given a
/// particular configuration and ambient state.
/// * [InheritedWidget], for widgets that introduce ambient state that can
/// be read by descendant widgets.
/// * [Widget], for an overview of widgets in general.
@optionalTypeArgs
abstract class State<T extends StatefulWidget> with Diagnosticable {
/// The current configuration.
///
/// A [State] object's configuration is the corresponding [StatefulWidget]
/// instance. This property is initialized by the framework before calling
/// [initState]. If the parent updates this location in the tree to a new
/// widget with the same [runtimeType] and [Widget.key] as the current
/// configuration, the framework will update this property to refer to the new
/// widget and then call [didUpdateWidget], passing the old configuration as
/// an argument.
T get widget => _widget!;
T? _widget;
/// The current stage in the lifecycle for this state object.
///
/// This field is used by the framework when asserts are enabled to verify
/// that [State] objects move through their lifecycle in an orderly fashion.
_StateLifecycle _debugLifecycleState = _StateLifecycle.created;
/// Verifies that the [State] that was created is one that expects to be
/// created for that particular [Widget].
bool _debugTypesAreRight(Widget widget) => widget is T;
/// The location in the tree where this widget builds.
///
/// The framework associates [State] objects with a [BuildContext] after
/// creating them with [StatefulWidget.createState] and before calling
/// [initState]. The association is permanent: the [State] object will never
/// change its [BuildContext]. However, the [BuildContext] itself can be moved
/// around the tree.
///
/// After calling [dispose], the framework severs the [State] object's
/// connection with the [BuildContext].
BuildContext get context {
assert(() {
if (_element == null) {
throw FlutterError(
'This widget has been unmounted, so the State no longer has a context (and should be considered defunct). \n'
'Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.',
);
}
return true;
}());
return _element!;
}
StatefulElement? _element;
/// Whether this [State] object is currently in a tree.
///
/// After creating a [State] object and before calling [initState], the
/// framework "mounts" the [State] object by associating it with a
/// [BuildContext]. The [State] object remains mounted until the framework
/// calls [dispose], after which time the framework will never ask the [State]
/// object to [build] again.
///
/// It is an error to call [setState] unless [mounted] is true.
bool get mounted => _element != null;
/// Called when this object is inserted into the tree.
///
/// The framework will call this method exactly once for each [State] object
/// it creates.
///
/// Override this method to perform initialization that depends on the
/// location at which this object was inserted into the tree (i.e., [context])
/// or on the widget used to configure this object (i.e., [widget]).
///
/// {@template flutter.widgets.State.initState}
/// If a [State]'s [build] method depends on an object that can itself
/// change state, for example a [ChangeNotifier] or [Stream], or some
/// other object to which one can subscribe to receive notifications, then
/// be sure to subscribe and unsubscribe properly in [initState],
/// [didUpdateWidget], and [dispose]:
///
/// * In [initState], subscribe to the object.
/// * In [didUpdateWidget] unsubscribe from the old object and subscribe
/// to the new one if the updated widget configuration requires
/// replacing the object.
/// * In [dispose], unsubscribe from the object.
///
/// {@endtemplate}
///
/// You should not use [BuildContext.dependOnInheritedWidgetOfExactType] from this
/// method. However, [didChangeDependencies] will be called immediately