diff --git a/packages/flutter/lib/src/material/reorderable_list.dart b/packages/flutter/lib/src/material/reorderable_list.dart index a2430c7004..7e901c4d96 100644 --- a/packages/flutter/lib/src/material/reorderable_list.dart +++ b/packages/flutter/lib/src/material/reorderable_list.dart @@ -4,9 +4,8 @@ import 'dart:math'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter/rendering.dart'; import 'debug.dart'; import 'material.dart'; @@ -345,11 +344,7 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T // Handles up the logic for dragging and reordering items in the list. Widget _wrap(Widget toWrap, int index, BoxConstraints constraints) { assert(toWrap.key != null); - final _ScopedValueGlobalKey<_ReorderableListContentState> keyIndexGlobalKey = - _ScopedValueGlobalKey<_ReorderableListContentState>( - scope: this, - value: toWrap.key, - ); + final GlobalObjectKey keyIndexGlobalKey = GlobalObjectKey(toWrap.key); // We pass the toWrapWithGlobalKey into the Draggable so that when a list // item gets dragged, the accessibility framework can preserve the selected // state of the dragging item. @@ -579,32 +574,3 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T }); } } - -/// A [GlobalKey] that uses a scope and a value to determine equality. -/// -/// The scope is compared using [identical], while the value is compared -/// using [operator ==]. This allows a locally scoped value to be turned -/// into a globally unique key. -class _ScopedValueGlobalKey> extends GlobalKey { - const _ScopedValueGlobalKey({this.scope, this.value}) : super.constructor(); - - final Object scope; - final Object value; - - @override - int get hashCode => hashValues(identityHashCode(scope), value.hashCode); - - @override - bool operator ==(dynamic other) { - if (other.runtimeType != runtimeType) { - return false; - } - final _ScopedValueGlobalKey typedOther = other; - return identical(scope, typedOther.scope) && value == typedOther.value; - } - - @override - String toString() { - return '[$runtimeType ${describeIdentity(scope)} ${describeIdentity(value)}]'; - } -} diff --git a/packages/flutter/test/material/reorderable_list_test.dart b/packages/flutter/test/material/reorderable_list_test.dart index 5027d1d905..b765d240f0 100644 --- a/packages/flutter/test/material/reorderable_list_test.dart +++ b/packages/flutter/test/material/reorderable_list_test.dart @@ -655,51 +655,6 @@ void main() { expect(findState(const Key('A')).checked, true); }); - testWidgets('Preserves children states across reorder when keys are not identical', (WidgetTester tester) async { - _StatefulState findState(Key key) { - return find.byElementPredicate((Element element) => element.ancestorWidgetOfExactType(_Stateful)?.key == key) - .evaluate() - .first - .ancestorStateOfType(const TypeMatcher<_StatefulState>()); - } - await tester.pumpWidget(MaterialApp( - home: ReorderableListView( - children: [ - _Stateful(key: const ObjectKey('A')), - _Stateful(key: const ObjectKey('B')), - _Stateful(key: const ObjectKey('C')), - ], - onReorder: (int oldIndex, int newIndex) { }, - scrollDirection: Axis.horizontal, - ), - )); - await tester.tap(find.byKey(const ObjectKey('A'))); - await tester.pumpAndSettle(); - // Only the 'A' widget should be checked. - expect(findState(const ObjectKey('A')).checked, true); - expect(findState(const ObjectKey('B')).checked, false); - expect(findState(const ObjectKey('C')).checked, false); - - // Rebuild with distinct key objects. - await tester.pumpWidget(MaterialApp( - home: ReorderableListView( - children: [ - // Deliberately avoid the const constructor below to ensure keys are - // distinct objects. - _Stateful(key: ObjectKey('B')), // ignore:prefer_const_constructors - _Stateful(key: ObjectKey('C')), // ignore:prefer_const_constructors - _Stateful(key: ObjectKey('A')), // ignore:prefer_const_constructors - ], - onReorder: (int oldIndex, int newIndex) { }, - scrollDirection: Axis.horizontal, - ), - )); - // Only the 'A' widget should be checked. - expect(findState(const ObjectKey('B')).checked, false); - expect(findState(const ObjectKey('C')).checked, false); - expect(findState(const ObjectKey('A')).checked, true); - }); - group('Accessibility (a11y/Semantics)', () { Map getSemanticsActions(int index) { final Semantics semantics = find.ancestor(