多个小部件在TabController中使用了相同的GlobalKey



我试图在启动应用程序时通过sharedpreferences检索初始索引来设置初始索引。但我有一条错误消息:

I/flutter(19911):══╡小部件库捕获的异常╞═══════════════════════════════════════════════════════════I/flutter(19911):在构建RawGestureDetector时抛出了以下断言(状态:I/flutter(19911):RawGestureDetectorState#438bc(手势:[敲击],行为:不透明):I/flutter(19911):多个小部件使用相同的GlobalKey。I/flutter(19911):键[GlobalKey#1b0d6]被多个小部件使用。这些小部件的父级是:I/flutter(19911):-填充(填充:EdgeInsets(16.0,0.0,16.0,10.0),renderObject:RenderAdding#61119 NEEDS-LAYOUTI/flutter(19911):取消需求保护)I/flutter(19911):-填充(填充:EdgeInsets(16.0,0.0,16.0,10.0),renderObject:RenderAdding#b3fbc NEEDS-LAYOUTI/flutter(19911):需要保护)I/flutter(19911):在小部件树中,一次只能在一个小部件上指定GlobalKey。

这是我的代码:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:dynamic_theme/dynamic_theme.dart';
import 'package:my_pau/widgets/tabs/tab_playground.dart';
import 'package:my_pau/widgets/tabs/tab_public_bench.dart';
import 'package:my_pau/widgets/tabs/tab_public_toilet.dart';
import 'package:my_pau/widgets/tabs/tab_car_park.dart';
import 'package:my_pau/widgets/tabs/tab_car_pay_machine.dart';
import 'package:my_pau/widgets/drawer_widget.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() async {
// Force the layout to Portrait mode
await SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appTitle = 'My Pau';
ThemeData _buildTheme(Brightness brightness) {
return brightness == Brightness.dark
? ThemeData.dark().copyWith(
textTheme: ThemeData.dark().textTheme.apply(
bodyColor: Colors.white,
displayColor: Colors.white,
fontFamily: 'Basier',
),
primaryColor: Colors.teal,
accentColor: Colors.tealAccent,
primaryColorDark: Colors.teal,
backgroundColor: Colors.black)
: ThemeData.light().copyWith(
textTheme: ThemeData.light().textTheme.apply(
bodyColor: Colors.black,
displayColor: Colors.black,
fontFamily: 'Basier',
),
primaryColor: Colors.teal,
accentColor: Colors.tealAccent,
backgroundColor: Colors.white);
}
return DynamicTheme(
defaultBrightness: Brightness.light,
data: (brightness) => _buildTheme(brightness),
themedWidgetBuilder: (context, theme) {
return MaterialApp(
debugShowCheckedModeBanner: false,
localizationsDelegates: [
// ... app-specific localization delegate[s] here
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('fr', 'FR'), // French
],
title: appTitle,
theme: theme,
home: MyHomePage(title: appTitle),
);
});
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
Map<String, int> views = {
'playground' : 0,
'publicToilet' : 1,
'carPark' : 2,
'carPayMachine' : 3,
'publicBench' : 4,
};
final List<Tab> _myTabs = <Tab>[
Tab(icon: Icon(Icons.child_care), text: "Aire de jeux"),
Tab(icon: Icon(Icons.wc), text: "WC publics"),
Tab(icon: Icon(Icons.local_parking), text: "Parkings"),
Tab(icon: Icon(Icons.departure_board), text: "Horodateurs"),
Tab(icon: Icon(Icons.event_seat), text: "Bancs publics"),
];
TabController _tabController;
static const String _sharedPreferencesKeyView = 'view';
String _defaultView;
@override
void initState() {
// _tabController = TabController(vsync: this, length: _myTabs.length, initialIndex: 3); ==> If I put this here it works
_loadDefaultSettings().then((value) {
_tabController = TabController(vsync: this, length: _myTabs.length, initialIndex: views[_defaultView]);
});
super.initState();
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
//Loading default settings value on start
Future<void> _loadDefaultSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_defaultView =
(prefs.getString(_sharedPreferencesKeyView) ?? 'playground');
});
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 5,
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
bottom: TabBar(
controller: _tabController,
isScrollable: true,
tabs: _myTabs,
),
),
body: TabBarView(
controller: _tabController,
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
TabPlayground(),
TabPublicToilet(),
TabCarPark(),
TabCarPayMachine(),
TabPublicBench(),
],
),
drawer: DrawerWidget(),
),
);
}
}

我该如何避免这种情况?我的目标是在启动应用程序时根据存储在sharedpreferences中的值显示正确的选项卡;)

我用一个小技巧解决了我的问题!当小部件的构建完成时,我为TabController设置了动画。

@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) => executeAfterWholeBuildProcess());
return DefaultTabController(BuildContext context){...}
void _executeAfterWholeBuildProcess() {
if (views[_defaultView] != null)
_tabController.animateTo(views[_defaultView],
duration: Duration(seconds: 1), curve: Curves.linear);
}

最新更新