首页 > 解决方案 > 在 Flutter CupertinoTabBar + StreamBuilder 中,代码正在运行,但未重建小部件

问题描述

我有一个 2 选项卡屏幕,我想根据用户的交互动态重建内容。在第一个选项卡上,我尝试通过使用模型和提供程序设置当前步骤名称来处理多个状态。对于按下按钮后的第二个屏幕,我在控制台中收到打印消息,但 CupertinoTabView 的内容保持不变。

最小可运行代码片段:

主要.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'package:my_app/screens/login.dart';
import 'package:my_app/screens/tab_bar.dart';
import 'package:my_app/models/model.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);

  return runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (context) => Model(),
        ),
      ],
      child: CupertinoApp(
        theme: const CupertinoThemeData(
          brightness: Brightness.light,
          scaffoldBackgroundColor: CupertinoColors.white,
        ),
        initialRoute: '/',
        routes: {
          '/': (context) => LoginScreen(),
          '/tab_bar': (context) => TabBarScreen(),
          //'/add_item': (context) => AddItemScreen(),
        },
      ),
    );
  }
}

登录.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'package:my_app/models/model.dart';

class LoginScreen extends StatelessWidget {
  final model = Model();

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('app',),
      ),
      child: Container(
        alignment: FractionalOffset.center,
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                child: Text('next'),
                onPressed: (){
                  model.setStep('step1');
                  Navigator.pushNamed(context, '/tab_bar');
                },
                style: ElevatedButton.styleFrom(
                    primary: CupertinoColors.white,
                    side: BorderSide(color: Colors.blue, width: 2.0)
                ),
              ),
            ]
        ),
      ),
    );
  }
}

tab_bar.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:my_app/models/model.dart';

class TabBarScreen extends StatefulWidget {
  @override
  State createState() => TabBarScreenState();
}

class TabBarScreenState extends State<TabBarScreen> {
  final model = Model();

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    print(model.getStep);
    return Consumer<Model>(
      builder: (context, model, _) => CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          backgroundColor: CupertinoColors.white,
          inactiveColor: Colors.blue,
          activeColor: Colors.blueAccent,
          border: const Border(
            top: BorderSide(
              color: CupertinoColors.activeBlue,
              width: 2.0,
            ),
          ),
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(Icons.favorite_outline_outlined),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.more_vert_sharp),
            ),
          ],
        ),
        tabBuilder: (context, index) {
          late final CupertinoTabView returnValue;
          switch (index) {
            case 0:
              if (model.getStep == 'step1') {
                print('step1');
                returnValue = CupertinoTabView(builder: (context) {
                  return CupertinoPageScaffold(
                    child: SafeArea(
                      child: GestureDetector(
                        onTap: (){  },
                        child: Column(
                          children: <Widget>[
                            Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: <Widget>[
                                Container(
                                  margin: const EdgeInsets.only(bottom: 15.0),
                                  child: FloatingActionButton(
                                    onPressed: () { model.setStep('step2'); setState(() {

                                    }); },
                                    tooltip: 'step2',
                                    child: Icon(Icons.add),
                                    backgroundColor: CupertinoColors.white,
                                    foregroundColor: CupertinoColors.black,
                                  ),
                                ),
                              ],
                            ),
                          ],
                        ),
                      ),
                    ),
                  );
                });
              }
              else if (model.getStep == 'step2') {
                print('step2');
                returnValue = CupertinoTabView(builder: (context) {
                  return CupertinoPageScaffold(
                    child: SafeArea(
                      child: Column(
                        children: <Widget> [
                          Text('step2'),
                        ],
                      ),
                    ),
                  );
                });
              }
              else {
                returnValue = CupertinoTabView(builder: (context) {
                  return Container();
                });
              }
              break;
            case 1:
              returnValue = CupertinoTabView(builder: (context) {
                return CupertinoPageScaffold(
                  child: Text("Tab2"),
                );
              });
              break;
          }
          return returnValue;
        },
      ),
    );
  }
}

模型.dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class Model extends ChangeNotifier {
  static String currentStep = 'login';
  // login
  // step1                      - step1
  // step2                      - step2


  String get getStep {
    return currentStep;
  }

  void setStep(String step) {
    currentStep = step;
    notifyListeners();
  }
}

我希望在按下 step1 中的按钮以显示 step2 内容时重建选项卡。在控制台中,按下时我可以看到“step2”的打印,但实际选项卡保持不变。感谢你的帮助

标签: flutterdart

解决方案


由于没有人回答,我自己想通了。解决方法是像这样使用 Navigator:

onPressed: () {
  Navigator.of(context).push(
    CupertinoPageRoute<void>(
      builder: (BuildContext context) {
        return CupertinoPageScaffold(
          navigationBar: CupertinoNavigationBar(
            middle: Text('Page 2 of tab'),
          ),
          child: Center(
            child: CupertinoButton(
              child: const Text('Back'),
              onPressed: () { Navigator.of(context).pop(); },
            ),
          ),
        );
      },
    ),
  );
},

因此您不需要“else if”调节。


推荐阅读