【问题标题】:Multiple widgets used the same GlobalKey with TabController多个小部件使用相同的 GlobalKey 和 TabController
【发布时间】:2019-06-01 09:17:34
【问题描述】:

我试图在启动应用程序时通过共享首选项检索此索引来设置初始索引。但是我有这个错误信息:

I/flutter (19911): ══╡ 小部件库发现异常╞════════════════════════════════════ ════════════════════════════ I/flutter (19911):在构建 RawGestureDetector(state: 我/颤振(19911):RawGestureDetectorState#438bc(手势:[点击],行为:不透明)): I/flutter (19911):多个小部件使用相同的 GlobalKey。 I/flutter (19911):键 [GlobalKey#1b0d6] 被多个小部件使用。这些小部件的父母是: I/flutter (19911): - Padding(padding: E​​dgeInsets(16.0, 0.0, 16.0, 0.0), renderObject: RenderPadding#61119 需要布局 我/颤振(19911):需要油漆分离) I/flutter (19911): - 填充(填充:EdgeInsets(16.0, 0.0, 16.0, 0.0),renderObject:RenderPadding#b3fbc NEEDS-LAYOUT 我/颤振(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(),
      ),
    );
  }
}

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

【问题讨论】:

    标签: dart flutter widget sharedpreferences tabcontrol


    【解决方案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);
      }
    

    【讨论】:

      猜你喜欢
      • 2018-09-26
      • 2019-06-07
      • 2020-10-01
      • 1970-01-01
      • 2021-08-26
      • 2023-03-04
      • 2020-10-21
      • 2021-07-01
      • 2019-05-27
      相关资源
      最近更新 更多