// 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. import 'dart:ui' show hashValues; import 'package:meta/meta.dart'; /// A [Key] is an identifier for [Widget]s, [Element]s and [SemanticsNode]s. /// /// A new widget will only be used to update an existing element if its key is /// the same as the key of the current widget associated with the element. /// /// {@youtube 560 315 https://www.youtube.com/watch?v=kn0EOS-ZiIc} /// /// Keys must be unique amongst the [Element]s with the same parent. /// /// Subclasses of [Key] should either subclass [LocalKey] or [GlobalKey]. /// /// See also: /// /// * [Widget.key], which discusses how widgets use keys. @immutable abstract class Key { /// Construct a [ValueKey<String>] with the given [String]. /// /// This is the simplest way to create keys. const factory Key(String value) = ValueKey<String>; /// Default constructor, used by subclasses. /// /// Useful so that subclasses can call us, because the [new Key] factory /// constructor shadows the implicit constructor. @protected const Key.empty(); } /// A key that is not a [GlobalKey]. /// /// Keys must be unique amongst the [Element]s with the same parent. By /// contrast, [GlobalKey]s must be unique across the entire app. /// /// See also: /// /// * [Widget.key], which discusses how widgets use keys. abstract class LocalKey extends Key { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. const LocalKey() : super.empty(); } /// A key that uses a value of a particular type to identify itself. /// /// A [ValueKey<T>] is equal to another [ValueKey<T>] if, and only if, their /// values are [operator==]. /// /// This class can be subclassed to create value keys that will not be equal to /// other value keys that happen to use the same value. If the subclass is /// private, this results in a value key type that cannot collide with keys from /// other sources, which could be useful, for example, if the keys are being /// used as fallbacks in the same scope as keys supplied from another widget. /// /// See also: /// /// * [Widget.key], which discusses how widgets use keys. class ValueKey<T> extends LocalKey { /// Creates a key that delegates its [operator==] to the given value. const ValueKey(this.value); /// The value to which this key delegates its [operator==] final T value; @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) return false; return other is ValueKey<T> && other.value == value; } @override int get hashCode => hashValues(runtimeType, value); @override String toString() { final String valueString = T == String ? "<'$value'>" : '<$value>'; // The crazy on the next line is a workaround for // https://github.com/dart-lang/sdk/issues/33297 if (runtimeType == _TypeLiteral<ValueKey<T>>().type) return '[$valueString]'; return '[$T $valueString]'; } } class _TypeLiteral<T> { Type get type => T; }