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
5/// @docImport 'package:flutter/semantics.dart';
6/// @docImport 'package:flutter/widgets.dart';
7library;
8
9import 'package:meta/meta.dart';
10
11import 'diagnostics.dart';
12
13/// A [Key] is an identifier for [Widget]s, [Element]s and [SemanticsNode]s.
14///
15/// A new widget will only be used to update an existing element if its key is
16/// the same as the key of the current widget associated with the element.
17///
18/// {@youtube 560 315 https://www.youtube.com/watch?v=kn0EOS-ZiIc}
19///
20/// Keys must be unique amongst the [Element]s with the same parent.
21///
22/// Subclasses of [Key] should either subclass [LocalKey] or [GlobalKey].
23///
24/// See also:
25///
26/// * [Widget.key], which discusses how widgets use keys.
27@immutable
28@pragma('flutter:keep-to-string-in-subtypes')
29abstract class Key {
30 /// Construct a [ValueKey<String>] with the given [String].
31 ///
32 /// This is the simplest way to create keys.
33 const factory Key(String value) = ValueKey<String>;
34
35 /// Default constructor, used by subclasses.
36 ///
37 /// Useful so that subclasses can call us, because the [Key.new] factory
38 /// constructor shadows the implicit constructor.
39 @protected
40 const Key.empty();
41}
42
43/// A key that is not a [GlobalKey].
44///
45/// Keys must be unique amongst the [Element]s with the same parent. By
46/// contrast, [GlobalKey]s must be unique across the entire app.
47///
48/// See also:
49///
50/// * [Widget.key], which discusses how widgets use keys.
51abstract class LocalKey extends Key {
52 /// Abstract const constructor. This constructor enables subclasses to provide
53 /// const constructors so that they can be used in const expressions.
54 const LocalKey() : super.empty();
55}
56
57/// A key that is only equal to itself.
58///
59/// This cannot be created with a const constructor because that implies that
60/// all instantiated keys would be the same instance and therefore not be unique.
61class UniqueKey extends LocalKey {
62 /// Creates a key that is equal only to itself.
63 ///
64 /// The key cannot be created with a const constructor because that implies
65 /// that all instantiated keys would be the same instance and therefore not
66 /// be unique.
67 // ignore: prefer_const_constructors_in_immutables , never use const for this class
68 UniqueKey();
69
70 @override
71 String toString() => '[#${shortHash(this)}]';
72}
73
74/// A key that uses a value of a particular type to identify itself.
75///
76/// A [ValueKey<T>] is equal to another [ValueKey<T>] if, and only if, their
77/// values are [operator==].
78///
79/// This class can be subclassed to create value keys that will not be equal to
80/// other value keys that happen to use the same value. If the subclass is
81/// private, this results in a value key type that cannot collide with keys from
82/// other sources, which could be useful, for example, if the keys are being
83/// used as fallbacks in the same scope as keys supplied from another widget.
84///
85/// See also:
86///
87/// * [Widget.key], which discusses how widgets use keys.
88class ValueKey<T> extends LocalKey {
89 /// Creates a key that delegates its [operator==] to the given value.
90 const ValueKey(this.value);
91
92 /// The value to which this key delegates its [operator==]
93 final T value;
94
95 @override
96 bool operator ==(Object other) {
97 if (other.runtimeType != runtimeType) {
98 return false;
99 }
100 return other is ValueKey<T>
101 && other.value == value;
102 }
103
104 @override
105 int get hashCode => Object.hash(runtimeType, value);
106
107 @override
108 String toString() {
109 final String valueString = T == String ? "<'$value'>" : '<$value>';
110 // The crazy on the next line is a workaround for
111 // https://github.com/dart-lang/sdk/issues/33297
112 if (runtimeType == _TypeLiteral<ValueKey<T>>().type) {
113 return '[$valueString]';
114 }
115 return '[$T $valueString]';
116 }
117}
118
119class _TypeLiteral<T> {
120 Type get type => T;
121}
122