skip to Main Content

Bloc Listner Does Not change state to navigate to next screen

  1. Bloc

    import 'package:bloc/bloc.dart';
    import 'package:bloctest/bloc/events.dart';
    import 'package:bloctest/bloc/states.dart';
    
    class AppBloc extends Bloc<AppEvent,AppState>{
    
      AppBloc(AppState initialState):super(initialState){
    
        on<AppStartEvent>((event, emit) {
          emit(AppInitState());
        });
    
        on<NavigatorButtonPressed>((event, emit) {
          emit(NavigationSucceedState());
          print('navigation succeed');
        });
      }
    }
    
  2. Bloc Listner screen

    import 'package:bloctest/bloc/bloc.dart';
    import 'package:bloctest/bloc/states.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    import 'bloc/events.dart';
    import 'main2.dart';
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      bool isNavigationSuccess=false;
      AppBloc appBloc=AppBloc(AppInitState());
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: BlocProvider<AppBloc>(
              create: (context)=>AppBloc(AppInitState())..add(AppStartEvent()),
              child: Scaffold(
                body: BlocListener<AppBloc, AppState>(
                  listener: (context , state)async{
    
                    if(state is NavigationSucceedState){
                   await Future.delayed(const Duration(seconds: 1));
                      Navigator.push(context, MaterialPageRoute(builder: (context)=>MyApp2()));
                    }
                  },
                  child:BlocBuilder<AppBloc,AppState>(
                  builder:(context,state){
                  context.read<AppBloc>().add(AppStartEvent());
                  return state is AppStartingState?const Center(child: CircularProgressIndicator(),):
                  Scaffold(
                        body: SafeArea(child: Center(
                          child: ElevatedButton(
                              onPressed: () {
                               appBloc.add(NavigatorButtonPressed());
                              },
                              child: const Text('tap to go to next page')),
                        )),
                      );
                   }
                ),
              ),
    
          ),
        )
        );
      }
    }
    
  3. How to Solve this issue, I want to Navigate to next screen after bloclistner check state, but in my ui bloc listner doesnot know about state is changed, therefore state is changed on<event>((state,emit)) after emiting to next state.

2

Answers


  1. Try this:

    class AppBloc extends Bloc<AppEvent,AppState>{
    
      AppBloc() : super(AppStartingState()){
    
        on<NavigatorButtonPressed>((event, emit) {
          emit(NavigationSucceedState());
          print('navigation succeed');
        });
      }
    }
    

    In UI:

    class _MyAppState extends State<MyApp> {
      bool isNavigationSuccess = false;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: BlocProvider<AppBloc>(
            create: (context) => AppBloc(),
            child: BlocListener<AppBloc, AppState>(
              listener: (context, state) {
                if (state is NavigationSucceedState) {
                  Future.delayed(const Duration(seconds: 1), () {
                    Navigator.push(
                        context, MaterialPageRoute(builder: (context) => MyApp2()));
                  });
                }
              },
              child: BlocBuilder<AppBloc, AppState>(
                builder: (context, state) => state is AppStartingState
                    ? const Center(child: CircularProgressIndicator())
                    : Scaffold(
                        body: SafeArea(
                          child: Center(
                            child: ElevatedButton(
                                onPressed: () {
                                  context.read<AppBloc>.add(
                                    NavigatorButtonPressed(),
                                  );
                                },
                                child: const Text('tap to go to next page')),
                          ),
                        ),
                      ),
              ),
            ),
          ),
        );
      }
    }
    
    Login or Signup to reply.
  2. Reason of the problem is the instance of the bloc, if you take a look you have created on instance in you state (AppBloc appBloc=AppBloc(AppInitState());) and other one in provide constructor (create: (context)=>AppBloc(AppInitState())..add(AppStartEvent()),) so if you can see in listener you are listening states change from second bloc instance but you are adding event to your first instance , and as they are different objects state changing from one is not available in second, so you on you on tap method you can add event to your provided bloc by context.read().add and it will work.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search