flutterflutter-bloc

Want to update ListView on index click in bloc flutter


I've make a about us page in my flutter application where terms,policy & other sections are listed and on click of them I store that index in some variable & I want to open its description below section name.

I successfully done it by using valuenotifier but now I want to convert in into Bloc.

Below are my files,

AboutUsState.dart

    import 'package:equatable/equatable.dart';
    import 'package:flutter/material.dart';
    import '../../../Model/ModelInformation.dart';
    
    @immutable
    abstract class AboutUsState extends Equatable {}
    
    class AboutUsLoadingState extends AboutUsState {
      @override
      List<Object?> get props => [];
    }
    
    class AboutUsLoadedState extends AboutUsState {
    
      final ModelInformation modelInformation;
        AboutUsLoadedState(this.modelInformation);
      @override
      List<Object?> get props => [modelInformation];
    }
    
    class AboutUsErrorState extends AboutUsState {
    
      final String error;
      AboutUsErrorState(this.error);
      @override
      List<Object?> get props => [error];
    
    }

AboutUsEvent.dart

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

@immutable
abstract class AboutUsEvent extends Equatable {
  const AboutUsEvent();
}

class LoadAboutUsEvent extends AboutUsEvent {
  @override
  List<Object?> get props => [];
}

class UpdateSelectedViewEvent extends AboutUsEvent {

  @override
  List<Object?> get props => [];
}

AboutUsBloc.dart

import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../Model/ModelInformation.dart';
import 'AboutUsEvent.dart';
import 'AboutUsState.dart';
import 'Repository.dart';

class AboutUsBloc extends Bloc<AboutUsEvent,AboutUsState> {

  final Repository repository;
    int selectedView = -1;

  AboutUsBloc(this.repository,this.selectedView) : super(AboutUsLoadingState()) {

    on<LoadAboutUsEvent>((event, emit) async {

        emit(AboutUsLoadingState());

        try {
          var dict = await repository.getAboutUs();
          final ModelInformation modelInformation = ModelInformation.fromJson(dict["mainResponse"]);

          emit(AboutUsLoadedState(modelInformation));
        } catch (e) {
          emit(AboutUsErrorState(e.toString()));
        }

    }
    );

  }
}

Repository.dart

import '../../../Services/ServiceManager.dart';
import '../../../Util/Constant.dart';

class Repository {

  Future getAboutUs() async {

   return await ServiceManager.callWebservice(
        varMethodType: enumMethodType.POST,
        strSuffixPath: ConstantApi.keyGetAboutUs,
        dictParameters: {},
        dictHeaders: {},
        arrayUploadFile: []
    );
  }

}

AboutUs.dart

import 'package:flutter_bloc/flutter_bloc.dart';
import '../../Model/ModelInformation.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../Util/Constant.dart';
import 'AboutUs/AboutUsBloc.dart';
import 'AboutUs/AboutUsEvent.dart';
import 'AboutUs/AboutUsState.dart';
import 'AboutUs/Repository.dart';

class ClassAboutUs extends StatefulWidget {
  @override
  stateClassAboutUs createState() => stateClassAboutUs();
}

class stateClassAboutUs extends State<ClassAboutUs> {

  final AboutUsBloc aboutUsBloc = AboutUsBloc(Repository(),-1);

  @override
  void initState() {
    super.initState();
    aboutUsBloc.add(LoadAboutUsEvent());
  }

  @override
  Widget build(BuildContext context) {

    return

      WillPopScope(
        onWillPop: ()  async{
          Navigator.pop(context);
          return true;
        },

        child: new Scaffold(
          backgroundColor: Theme.of(context).colorScheme.background,

          appBar: AppBar(
            elevation: 0.5,
            backgroundColor: Theme.of(context).colorScheme.background,
            titleSpacing: 0,
            centerTitle: false,
            leading: BackButton(
              color: Theme.of(context).colorScheme.onBackground.withOpacity(0.87),
              onPressed: (){
                Navigator.pop(context);
              },
            ),
            title: Text("About us",

              style: TextStyle(
                color: Theme.of(context).colorScheme.onBackground.withOpacity(0.87),
                fontFamily: ConstantFont.keyPrimaryFont,
                fontSize: 15,
                fontWeight: FontWeight.w400,
              ),
            ),
          ),
          body:
          BlocProvider(
              create: (_) => aboutUsBloc,

            child: BlocBuilder<AboutUsBloc, AboutUsState>(

              builder: (context, state) {
                if (state is AboutUsLoadingState) {
                  return const Center(
                    child: CircularProgressIndicator(),
                  );
                }
                if (state is AboutUsErrorState) {
                  return const Center(child:  Text("Error"));
                }
                if (state is AboutUsLoadedState) {

                  ModelInformation modelInformation = state.modelInformation;
                  return ListView.builder(
                    padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
                    itemCount: modelInformation.mainmenu!.informationPages!.length,
                    itemBuilder: (context, index) {

                        return

                        aboutUsBloc.selectedView == index ?
                        Container(
                            color: Theme.of(context).colorScheme.primary.withOpacity(0.10),
                            child: Column(

                              crossAxisAlignment: CrossAxisAlignment.start,

                              children: [

                                InkWell(
                                  onTap: (){
                                    aboutUsBloc.selectedView = aboutUsBloc.selectedView== index ? -1 : index;

                                  },
                                  child:
                                  Padding(
                                      padding: const EdgeInsets.all(10),
                                      child: Row(
                                        children: [

                                          Expanded(
                                            child: Text("${modelInformation.mainmenu!.informationPages![index].headingTitle}",style: ConstantTextStyle.h2.copyWith(fontWeight: FontWeight.w600,color: Theme.of(context).colorScheme.primary)),
                                          ),
                                          Padding(
                                            padding: EdgeInsets.only(left: 5,top: 5,bottom: 5),
                                            child: Icon(Icons.keyboard_arrow_up_rounded,size: 15,color: Theme.of(context).colorScheme.onBackground.withOpacity(0.60),),
                                          ),

                                        ],
                                      )
                                  ),),
                                Padding(
                                  padding: const EdgeInsets.only(left: 10,right: 10,),
                                  child: Text("${modelInformation.mainmenu!.informationPages![index].description}",style: ConstantTextStyle.h3.copyWith(color: Theme.of(context).colorScheme.onBackground.withOpacity(0.87)),
                                    textAlign: TextAlign.justify,
                                  ),
                                ),


                              ],
                            )
                        ) :

                         Column(

                          crossAxisAlignment: CrossAxisAlignment.start,

                          children: [

                            InkWell(
                              onTap: (){
                                  aboutUsBloc.selectedView = aboutUsBloc.selectedView == index ? -1 : index;
                                aboutUsBloc.add(UpdateSelectedViewEvent());
                              },
                              child:
                              Padding(
                                  padding: const EdgeInsets.all(10),
                                  child: Row(
                                    children: [

                                      Expanded(
                                        child: Text("${modelInformation.mainmenu!.informationPages![index].headingTitle}",style: ConstantTextStyle.h2.copyWith(fontWeight: FontWeight.w600,color: Theme.of(context).colorScheme.primary)),
                                      ),
                                      Padding(
                                        padding: EdgeInsets.only(left: 5,top: 5,bottom: 5),
                                        child: Icon(Icons.keyboard_arrow_down_rounded,size: 15,color: Theme.of(context).colorScheme.onBackground.withOpacity(0.60),),
                                      ),

                                    ],
                                  )
                              ),),
                            Divider(height: 1,color: Theme.of(context).colorScheme.onBackground.withOpacity(0.37),),

                          ],
                        );
                    },
                  );
                }

                return Container();
              },
            ),
          )

        ),
      );
  }

}

I want to update listview single block based on selectedView value changes


Solution

  • Create one more event for updating selection:

    class UpdateSelectedEvent extends AboutUsEvent {
      final int selectedView;
    
      UpdateSelectedEvent(this.selectedView);
    
      @override
      List<Object?> get props => [selectedView];
    }
    

    add this event to your bloc:

    on<UpdateSelectedEvent>((event, emit) {
        selectedView = event.selectedView;
        if(state is AboutUsLoadedState){
           emit(AboutUsLoadedState(state.modelInformation));
        }
      });
    

    and add the update event on onTap:

    onTap: () => aboutUsBloc.add(UpdateSelectedEvent(index)),