简体   繁体   中英

Flutter splash screen error - Navigator operation requested with a context that does not include a Navigator. How can I solve this error

Edit: (main.dart) Added Sentry which actually starts the app

 Future<void> main() async {
   await SentryFlutter.init(
    (options) {
      options.dsn = _sentryDSN;
      // Set tracesSampleRate to 1.0 to capture 100% of        transactions for performance monitoring.
      // We recommend adjusting this value in production.
      options.tracesSampleRate = _sentryTracesSampleRate;
      options.attachStacktrace = true;
      options.enableAppLifecycleBreadcrumbs = true;
      },
   appRunner: () => runApp(const SplashScreen()),
  );

   // or define SENTRY_DSN via Dart environment variable (--dart-define)
  }

New to flutter, creating a splash screen to an app that was built with MaterialApp but getting an error. HOw can I solve this without a onPress function

Error: 在此处输入图像描述

Exception has occurred. FlutterError (Navigator operation requested with a context that does not include a Navigator. The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.)

import 'package:flutter/material.dart';
import 'package:loopcycle/screens/loopcycle_main.dart';

class SplashScreen extends StatefulWidget {
  const SplashScreen({Key? key}) : super(key: key);

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
  super.initState();
  _navigateToMainApp();
}

void _navigateToMainApp() async {
  await Future.delayed(const Duration(milliseconds: 2000), () {
    Navigator.pushReplacement(context,
      MaterialPageRoute(builder: (context) => const LoopcycleMainApp()));
  });
}

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Builder(
      builder: (context) => const Center(
            child: Text("test"),
          )),
    );
  }
}

Thank you in advance.

EDIT: I changed the solution after you provided more information about the code.

This error is happening because you are using a context that does not have a Navigator in it, this is happening probrably because the widget that you are getting the context is parent of the MaterialApp() widget, to solve it you should create another widget that is a child of the MaterialApp() instead of using the parent widget, let me give you an example instead:

void main() {
    runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: GestureDetector(
        onTap: () => Navigator.of(context).push(
          MaterialPageRoute(
            builder: (context) => SomeWidget(),
          ),
       ),
        child: Container(
          height: 300,
          width: 300,
          color: Colors.red,
        ),
      ),
    );
  }
}

This may give an error because you are using the context of a widget that is the parent of the MaterialApp() widget, to solve it just create another widget that is a child of MaterialApp() .

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AnotherWidget(),
    );
  }
}

class AnotherWidget extends StatelessWidget {
  const AnotherWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () => Navigator.of(context).push(
          MaterialPageRoute(
            builder: (context) => SomeWidget(),
          ),
        ),
        child: Container(
          height: 300,
          width: 300,
          color: Colors.red,
        ),
      ),
    );
  }
}

I was playing with your code, and fixed it for you, and there are basically two ways to solve it, you can create a MaterialApp() before calling the SplashScreen() in the runApp() function like so:

import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:loopcycle/screens/loopcycle_main.dart';

Future<void> main() async {
  await SentryFlutter.init(
    (options) {
      options.dsn = _sentryDSN;
      // Set tracesSampleRate to 1.0 to capture 100% of        transactions for performance monitoring.
      // We recommend adjusting this value in production.
      options.tracesSampleRate = _sentryTracesSampleRate;
      options.attachStacktrace = true;
      options.enableAppLifecycleBreadcrumbs = true;
    },
    appRunner: () => runApp(
      const MaterialApp(
        home: SplashScreen(),
      ),
    ),
  );

  // or define SENTRY_DSN via Dart environment variable (--dart-define)
}

class SplashScreen extends StatefulWidget {
  const SplashScreen({Key? key}) : super(key: key);

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();
    _navigateToMainApp();
  }

  void _navigateToMainApp() async {
    await Future.delayed(const Duration(milliseconds: 2000), () {
      Navigator.pushReplacement(context,
          MaterialPageRoute(builder: (context) => const LoopcycleMainApp()));
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Builder(
          builder: (context) => const Center(
                child: Text("test"),
              )),
    );
  }
}

Or you can create an intermediate widget to hold the MaterialApp() and then inside this widget you can call SplashScreen() , like so:

import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:loopcycle/screens/loopcycle_main.dart';

Future<void> main() async {
  await SentryFlutter.init(
    (options) {
      options.dsn = _sentryDSN;
      // Set tracesSampleRate to 1.0 to capture 100% of        transactions for performance monitoring.
      // We recommend adjusting this value in production.
      options.tracesSampleRate = _sentryTracesSampleRate;
      options.attachStacktrace = true;
      options.enableAppLifecycleBreadcrumbs = true;
    },
    appRunner: () => runApp(const MyApp()),
  );

  // or define SENTRY_DSN via Dart environment variable (--dart-define)
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: SplashScreen(),
    );
  }
}

class SplashScreen extends StatefulWidget {
  const SplashScreen({Key? key}) : super(key: key);

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();
    _navigateToMainApp();
  }

  void _navigateToMainApp() async {
    await Future.delayed(const Duration(milliseconds: 2000), () {
      Navigator.pushReplacement(context,
          MaterialPageRoute(builder: (context) => const LoopcycleMainApp()));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Builder(
          builder: (context) => const Center(
                child: Text("test"),
              )),
    );
  }
}

In this second solution, the intermediate widget is the MyApp() widget, and in my opinion, I consider this solution as being the best one for your problem, because if you ever wanted to load a different screen based on the different states, for example:

If a user is signed in you load a home page, and if a user is not signed in you load a sign up page.

Doing this, or anything similar is much easier when you have this intermediate widget that holds the MaterialApp() , and you can even create some logic to integrate the Splash Screen too, but I don't know what you are trying to achieve, so pick the solution you find the best for your problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM