保存状态并防止启动不止一次

发布于 2025-01-22 15:18:26 字数 7223 浏览 0 评论 0原文

我有3页(所有状态窗口小部件):

  • 主页
  • 天气页面
  • 设置页面

是我从主页天气页面带有 navigator.pushmed“ ,从天气页面 主页 “ navigator.pop” ,下次我'我试图从主页 initstate 方法 再次称为,再次称为... 我如何仅第一次将其调用,并且每次推入天气页面时都不会被调用?

在这里我的app.dart代码:

import 'package:exomind/src/core/views/home_view.dart';
import 'package:exomind/src/features/weather/presentation/views/weather_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import '../injection_container.dart';
import 'core/styles/colors.dart';
import 'features/settings/presentation/bloc/settings_bloc.dart';
import 'features/settings/presentation/views/settings_view.dart';
import 'features/weather/presentation/bloc/weather_bloc.dart';

/// The Widget that configures your application.
class MyApp extends StatelessWidget {
  const MyApp({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // Glue the SettingsController to the MaterialApp.
    //
    // The AnimatedBuilder Widget listens to the SettingsController for changes.
    // Whenever the user updates their settings, the MaterialApp is rebuilt.

    return MultiBlocProvider(
        providers: [
          BlocProvider<WeatherBloc>(
              create: (_) => serviceLocator<WeatherBloc>()),
          BlocProvider<SettingsBloc>(
              create: (_) => serviceLocator<SettingsBloc>()
                ..add(
                  const SettingsLoaded(),
                )),
        ],
        child:
            BlocBuilder<SettingsBloc, SettingsState>(builder: (context, state) {
          return MaterialApp(
            debugShowCheckedModeBanner: false,

            // Providing a restorationScopeId allows the Navigator built by the
            // MaterialApp to restore the navigation stack when a user leaves and
            // returns to the app after it has been killed while running in the
            // background.
            restorationScopeId: 'app',

            // Provide the generated AppLocalizations to the MaterialApp. This
            // allows descendant Widgets to display the correct translations
            // depending on the user's locale.
            localizationsDelegates: const [
              AppLocalizations.delegate,
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              GlobalCupertinoLocalizations.delegate,
            ],
            supportedLocales: const [
              Locale('en', ''), // English, no country code
            ],

            // Use AppLocalizations to configure the correct application title
            // depending on the user's locale.
            //
            // The appTitle is defined in .arb files found in the localization
            // directory.
            onGenerateTitle: (BuildContext context) =>
                AppLocalizations.of(context)!.appTitle,

            // Define a light and dark color theme. Then, read the user's
            // preferred ThemeMode (light, dark, or system default) from the
            // SettingsController to display the correct theme.
            theme:
                ThemeData(fontFamily: 'Circular', primaryColor: kPrimaryColor),
            darkTheme: ThemeData.dark(),
            themeMode: state.themeMode,

            // Define a function to handle named routes in order to support
            // Flutter web url navigation and deep linking.
            onGenerateRoute: (RouteSettings routeSettings) {
              return MaterialPageRoute<void>(
                settings: routeSettings,
                builder: (BuildContext context) {
                  switch (routeSettings.name) {
                    case SettingsView.routeName:
                      return const SettingsView();
                    case WeatherView.routeName:
                      return const WeatherView();
                    case HomeView.routeName:
                      return const HomeView();
                    default:
                      return const HomeView();
                  }
                },
              );
            },
          );
        }));
  }
}

在这里我的home_view.dart代码:

import 'package:flutter/material.dart';

import '../../features/weather/presentation/views/weather_view.dart';

class HomeView extends StatefulWidget {
  const HomeView({Key? key}) : super(key: key);
  static const routeName = '/home';

  @override
  State<HomeView> createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView>
    with SingleTickerProviderStateMixin {
  late AnimationController rotationController;

  @override
  void initState() {
    rotationController =
        AnimationController(duration: const Duration(seconds: 1), vsync: this)
          ..repeat();
    super.initState();
  }

  @override
  void dispose() {
    rotationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double height = MediaQuery.of(context).size.height;
    final double width = MediaQuery.of(context).size.width;

    return Scaffold(
      body: Stack(
        alignment: Alignment.center,
        children: [
          Positioned(
            top: (height / 2),
            child: RotationTransition(
              turns: Tween(begin: 0.0, end: 1.0).animate(rotationController),
              child: IconButton(
                icon: const Icon(Icons.wb_sunny),
                color: Colors.yellow,
                iconSize: (width * 0.2),
                onPressed: () {
         Navigator.of(context).pushNamed(WeatherView.routeName);
                },
              ),
            ),
          )
        ],
      ),
    );
  }
}

在这里我的weather_view.dart代码:

import 'dart:async';
import 'package:exomind/src/features/weather/presentation/bloc/weather_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:percent_indicator/percent_indicator.dart';

class WeatherView extends StatefulWidget {
  const WeatherView({Key? key}) : super(key: key);
  static const routeName = '/weather';

  @override
  State<WeatherView> createState() => _WeatherViewState();
}

class _WeatherViewState extends State<WeatherView>
    with SingleTickerProviderStateMixin {

  @override
  void initState() {
    print("initcalled")
    super.initState();
  }

  @override
  void dispose() {
    rotationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);

    final double width = MediaQuery.of(context).size.width;
    final double height = MediaQuery.of(context).size.height;

    return Scaffold();
  }
}

任何帮助和解释都会受到赞赏: )

I have 3 page (all statefull widgets) :

  • Home page
  • Weather page
  • Setting page

The things is when i'm going from home page to weather page with a "Navigator.pushNamed" and going from the weather page to home page with a "Navigator.pop", the next time i'm trying to go to the weather page from the home page, initState method is called again...
How i can manage to make it call only the first time and not been called every time i push into the weather page ?

Here my app.dart code :

import 'package:exomind/src/core/views/home_view.dart';
import 'package:exomind/src/features/weather/presentation/views/weather_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import '../injection_container.dart';
import 'core/styles/colors.dart';
import 'features/settings/presentation/bloc/settings_bloc.dart';
import 'features/settings/presentation/views/settings_view.dart';
import 'features/weather/presentation/bloc/weather_bloc.dart';

/// The Widget that configures your application.
class MyApp extends StatelessWidget {
  const MyApp({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // Glue the SettingsController to the MaterialApp.
    //
    // The AnimatedBuilder Widget listens to the SettingsController for changes.
    // Whenever the user updates their settings, the MaterialApp is rebuilt.

    return MultiBlocProvider(
        providers: [
          BlocProvider<WeatherBloc>(
              create: (_) => serviceLocator<WeatherBloc>()),
          BlocProvider<SettingsBloc>(
              create: (_) => serviceLocator<SettingsBloc>()
                ..add(
                  const SettingsLoaded(),
                )),
        ],
        child:
            BlocBuilder<SettingsBloc, SettingsState>(builder: (context, state) {
          return MaterialApp(
            debugShowCheckedModeBanner: false,

            // Providing a restorationScopeId allows the Navigator built by the
            // MaterialApp to restore the navigation stack when a user leaves and
            // returns to the app after it has been killed while running in the
            // background.
            restorationScopeId: 'app',

            // Provide the generated AppLocalizations to the MaterialApp. This
            // allows descendant Widgets to display the correct translations
            // depending on the user's locale.
            localizationsDelegates: const [
              AppLocalizations.delegate,
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              GlobalCupertinoLocalizations.delegate,
            ],
            supportedLocales: const [
              Locale('en', ''), // English, no country code
            ],

            // Use AppLocalizations to configure the correct application title
            // depending on the user's locale.
            //
            // The appTitle is defined in .arb files found in the localization
            // directory.
            onGenerateTitle: (BuildContext context) =>
                AppLocalizations.of(context)!.appTitle,

            // Define a light and dark color theme. Then, read the user's
            // preferred ThemeMode (light, dark, or system default) from the
            // SettingsController to display the correct theme.
            theme:
                ThemeData(fontFamily: 'Circular', primaryColor: kPrimaryColor),
            darkTheme: ThemeData.dark(),
            themeMode: state.themeMode,

            // Define a function to handle named routes in order to support
            // Flutter web url navigation and deep linking.
            onGenerateRoute: (RouteSettings routeSettings) {
              return MaterialPageRoute<void>(
                settings: routeSettings,
                builder: (BuildContext context) {
                  switch (routeSettings.name) {
                    case SettingsView.routeName:
                      return const SettingsView();
                    case WeatherView.routeName:
                      return const WeatherView();
                    case HomeView.routeName:
                      return const HomeView();
                    default:
                      return const HomeView();
                  }
                },
              );
            },
          );
        }));
  }
}

Here my home_view.dart code :

import 'package:flutter/material.dart';

import '../../features/weather/presentation/views/weather_view.dart';

class HomeView extends StatefulWidget {
  const HomeView({Key? key}) : super(key: key);
  static const routeName = '/home';

  @override
  State<HomeView> createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView>
    with SingleTickerProviderStateMixin {
  late AnimationController rotationController;

  @override
  void initState() {
    rotationController =
        AnimationController(duration: const Duration(seconds: 1), vsync: this)
          ..repeat();
    super.initState();
  }

  @override
  void dispose() {
    rotationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double height = MediaQuery.of(context).size.height;
    final double width = MediaQuery.of(context).size.width;

    return Scaffold(
      body: Stack(
        alignment: Alignment.center,
        children: [
          Positioned(
            top: (height / 2),
            child: RotationTransition(
              turns: Tween(begin: 0.0, end: 1.0).animate(rotationController),
              child: IconButton(
                icon: const Icon(Icons.wb_sunny),
                color: Colors.yellow,
                iconSize: (width * 0.2),
                onPressed: () {
         Navigator.of(context).pushNamed(WeatherView.routeName);
                },
              ),
            ),
          )
        ],
      ),
    );
  }
}

Here my weather_view.dart code :

import 'dart:async';
import 'package:exomind/src/features/weather/presentation/bloc/weather_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:percent_indicator/percent_indicator.dart';

class WeatherView extends StatefulWidget {
  const WeatherView({Key? key}) : super(key: key);
  static const routeName = '/weather';

  @override
  State<WeatherView> createState() => _WeatherViewState();
}

class _WeatherViewState extends State<WeatherView>
    with SingleTickerProviderStateMixin {

  @override
  void initState() {
    print("initcalled")
    super.initState();
  }

  @override
  void dispose() {
    rotationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);

    final double width = MediaQuery.of(context).size.width;
    final double height = MediaQuery.of(context).size.height;

    return Scaffold();
  }
}

Any help and explanation would be appreciate :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ペ泪落弦音 2025-01-29 15:18:26

我想不出一种“干净”的方式,即不在_weatherviewState中执行Initstate。您是否试图避免添加到WeatherBloc的同一城市不止一次?如果是这样,在添加之前,我会检查Weatherbloc中的“城市”。

I can't think of a "clean" way of not executing the initState in _WeatherViewState. Are you trying to avoid the same city added to the WeatherBloc more than once? If so, I'd check for the existence of 'city' in the WeatherBloc before adding.

梓梦 2025-01-29 15:18:26

在您的ongenerateroute中,您每次都会调用Weatherview构造函数:

case WeatherView.routeName:
  return const WeatherView();

依次调用Initstate。您需要做的是创建Weatherview page widget一次,然后在ongenerateroute中使用它:

final _weatherView = const WeatherView();

在您的ongererateroute中:

case WeatherView.routeName:
  return _weatherView;

In your onGenerateRoute you call the WeatherView constructor each time:

case WeatherView.routeName:
  return const WeatherView();

This in turn will call initState. What you need to do is create the WeatherView page widget once and use it in the onGenerateRoute:

final _weatherView = const WeatherView();

In your onGenerateRoute:

case WeatherView.routeName:
  return _weatherView;
此生挚爱伱 2025-01-29 15:18:26

正如@Roslanamir所说,每次我们进入状态范围时,都无法防止被调用。
因此,为了防止每次我们推入已陈述的小部件时,我都会添加到集团中的事件,我会向每个州添加一个布尔变量,以了解是否应该再次添加该事件。
对于那些想要一个精确答案的人,请不要犹豫。

As @RoslanAmir said there is no way to prevent initstate of been called each time we push into a statefulwidget.
So to prevent my event of being added into my bloc each time we push into the stateful widget i add a bool variable to each state to know if the event should be added or not again.
For those who want a precise answer don't hesitate.

相权↑美人 2025-01-29 15:18:26

只需在天气页面上添加一个参数:指定Rebuild true false 的布尔值。 (如果为true,它将调用initstate()

此代码正常工作。

class WeatherView extends StatefulWidget {
  final bool rebuild;
  static const routeName = '/weather';

  WeatherView({
    Key? key,
    required this.rebuild,
  }) : super(key: key);

  @override
  State<WeatherView> createState() => _WeatherViewState();
}

WeatherViewState's initstate()将是:

@override
void initState() {
  if (widget.rebuild) {
    print("initcalled");
    super.initState();
  } else {
    print("Not called");
  }
}

因此,在您的app.dart.dart中,您现在应该通过执行到页面来路由到页面

case WeatherView.routeName:
     return const WeatherView(rebuild: true); //Choose if rebuild or not by true and false

Just add a parameter to the Weather page: a boolean that specifies if the rebuild is true or false. (If true, it will call the initState())

This code works fine.

class WeatherView extends StatefulWidget {
  final bool rebuild;
  static const routeName = '/weather';

  WeatherView({
    Key? key,
    required this.rebuild,
  }) : super(key: key);

  @override
  State<WeatherView> createState() => _WeatherViewState();
}

and the WeatherViewState's initState() will be:

@override
void initState() {
  if (widget.rebuild) {
    print("initcalled");
    super.initState();
  } else {
    print("Not called");
  }
}

So, in your app.dart you should now route to the page by doing

case WeatherView.routeName:
     return const WeatherView(rebuild: true); //Choose if rebuild or not by true and false
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文