多个小部件通过TabController使用相同的GlobalKey

时间:2019-01-06 13:32:09

标签: dart flutter widget sharedpreferences tabcontrol

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

  

I / flutter(19911):══╡小子图书馆的例外情况╞═​​══════════════════════════════ ════════════════════════════   I / flutter(19911):构建RawGestureDetector(状态:   I / flutter(19911):RawGestureDetectorState#438bc(手势:[tap],行为:不透明)):   I / flutter(19911):多个小部件使用了相同的GlobalKey。   I / flutter(19911):键[GlobalKey#1b0d6]被多个小部件使用。这些小部件的父母是:   I / flutter(19911):-填充(padding:EdgeInsets(16.0,0.0,16.0,0.0),renderObject:RenderPadding#61119 NEEDS-LAYOUT   I / flutter(19911):已分离NEEDS-PAINT)   I / flutter(19911):-填充(填充:EdgeInsets(16.0、0.0、16.0、0.0),renderObject:RenderPadding#b3fbc NEEDS-LAYOUT   I / flutter(19911):NEEDS-PAINT)   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(),
      ),
    );
  }
}

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

1 个答案:

答案 0 :(得分:1)

我用一些小技巧解决了我的问题!小部件的构建完成后,为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);
  }