FlutterのIflutter-multiple-widgets-used-the-same-globalkey.
をなんとかしたい!
概要
今回の記事では、FlutterのMultiple widgets used the same GlobalKey.
をなんとかする手順を掲載する。
仕様書
環境
- Android Studio Giraffe | 2023.2.1 Patch 2
- Flutter 3.19.6
手順書
このエラーの原因はGlobalKey
が必要なウェジェットに設定されてない場合に発生する。
エラーが発生する例
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: const ReorderableListViewSample1()
)
)
);
}
class ReorderableListViewSample1 extends StatefulWidget {
const ReorderableListViewSample1({super.key});
@override
ReorderableListViewSample1State createState() => ReorderableListViewSample1State();
}
class ReorderableListViewSample1State extends State<ReorderableListViewSample1> {
List<String> list = ["Apple", "Bear", "Cat", "Decadence", "Exp", "File", "Godspeed", "Hex", "Iron" , "Joker", "Keep", "Leek", "Opaque", "Picnic", "Que", "Resonance", "Salt", "Tooth", "Under" ,"Vanguard", "Whisky", "Xray", "Zine"];
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: SizedBox(
width: double.infinity,
child: ReorderableListView(
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final item = list.removeAt(oldIndex);
list.insert(newIndex, item);
});
},
children: List.generate(list.length, (index) {
return Card(
child: ListTile(
title: Text(list[index])
),
);
}),
),
),
),
);
}
}
ReorderableListView
の子であるCard
にkey
が設定されてないためにMultiple widgets used the same GlobalKey.
が発生する。
エラーが発生しない例
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: const ReorderableListViewSample1()
)
)
);
}
class ReorderableListViewSample1 extends StatefulWidget {
const ReorderableListViewSample1({super.key});
@override
ReorderableListViewSample1State createState() => ReorderableListViewSample1State();
}
class ReorderableListViewSample1State extends State<ReorderableListViewSample1> {
List<String> list = ["Apple", "Bear", "Cat", "Decadence", "Exp", "File", "Godspeed", "Hex", "Iron" , "Joker", "Keep", "Leek", "Opaque", "Picnic", "Que", "Resonance", "Salt", "Tooth", "Under" ,"Vanguard", "Whisky", "Xray", "Zine"];
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: SizedBox(
width: double.infinity,
child: ReorderableListView(
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final item = list.removeAt(oldIndex);
list.insert(newIndex, item);
});
},
children: List.generate(list.length, (index) {
return Card(
key: ValueKey(list[index]),
child: ListTile(
title: Text(list[index])
),
);
}),
),
),
),
);
}
}
Card
のkey
にValueKey
を設定してる。この場合はGlobalKey
じゃなくてValueKey
でもいい。
GlobalKey
とValueKey
の違いは大雑把に説明すると有効なスコープが違う。GlobalKey
はウィジェットツリーの全体で、ValueKey
はローカルな範囲で一意性を担保するために使われる。他にも違いがあるんだけども、まあ、その、大体そんな感じ。
まとめ(感想文)
内部的に要素を判別するためにkey
が必要になるんだと思われ。