如何使用"全局对象键"滚动到某个小部件?现在他们抛出"Duplicate GlobalKeys"例外



我有一个屏幕,上面有一个小部件列表,它正在滚动以选择点击的元素。为了达到这个目的,我使用了Scrollable。ensureVisible和GlobalObjectKeys。除了一种情况外,它通常都很有效。如果我在滚动屏幕上用导航器再推一下这个屏幕。"在小部件树中检测到重复的GlobalKeys";错误(如果我推一些其他屏幕,然后我的滚动屏幕-一切都是好的)。但一切都很好-应用程序没有崩溃,滚动工作如预期。我找不到解决这个问题的方法。

最小可重现示例(只需点击FAB重现问题):

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _chipsScrollController = ScrollController();
String _currentChip = 'Chip 1';
static const _chips = [
'Chip 1',
'Chip 2',
'Chip 3',
'Chip 4',
'Chip 5',
'Chip 6',
'Chip 7',
'Chip 8',
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: SizedBox(
height: 70,
child: ListView.separated(
controller: _chipsScrollController,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
scrollDirection: Axis.horizontal,
itemCount: _chips.length,
itemBuilder: (final BuildContext context, final int index) {
return ChoiceChip(
key: GlobalObjectKey(_chips[index]),
label: Text(_chips[index]),
selected: _chips[index] == _currentChip,
onSelected: (final bool value) {
_currentChip = _chips[index];
Scrollable.ensureVisible(
GlobalObjectKey(_chips[index]).currentContext!,
alignment: 0.5,
);
});
},
separatorBuilder: (final BuildContext context, final int index) =>
const SizedBox(width: 12),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => const MyHomePage(
title: 'Flutter Demo Home Page',
),
),
),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

如果您确实需要这个(参见@YeasinSheikh的评论),您需要确保这些全局键在您的应用程序中是唯一的。为此,您可以向MyHomePage的每个实例添加一个GlobalKey,并将此键与用于Chip小部件的键结合使用。

试试这个代码:

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(key: GlobalKey(), title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
// add a required Key param to the constructor and pass it to super
const MyHomePage({required Key key, required this.title}): super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _chipsScrollController = ScrollController();
String _currentChip = 'Chip 1';
static const _chips = [
'Chip 1',
'Chip 2',
'Chip 3',
'Chip 4',
'Chip 5',
'Chip 6',
'Chip 7',
'Chip 8',
'Chip 9',
'Chip 10',
'Chip 11',
'Chip 12',
'Chip 13',
'Chip 14',
'Chip 15',
'Chip 16',
'Chip 18',
'Chip 19',
'Chip 20',
'Chip 21',
'Chip 22',
'Chip 23',
'Chip 24',     
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: SizedBox(
height: 70,
child: ListView.separated(
controller: _chipsScrollController,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
scrollDirection: Axis.horizontal,
itemCount: _chips.length,
itemBuilder: (final BuildContext context, final int index) {
return ChoiceChip(
// key now will be globally unique 
key: GlobalObjectKey('${widget.key}_${_chips[index]}'),
label: Text(_chips[index]),
selected: _chips[index] == _currentChip,
onSelected: (final bool value) {
_currentChip = _chips[index];
Scrollable.ensureVisible(
GlobalObjectKey('${widget.key}_${_chips[index]}').currentContext!,
alignment: 0.5,
);
});
},
separatorBuilder: (final BuildContext context, final int index) =>
const SizedBox(width: 12),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => MyHomePage(key: GlobalKey(),
title: 'Flutter Demo Home Page',
),
),
),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

相关内容

最新更新