Flutter Navigator.pop() 保持对话框部分可见,黑色阴影背景

Posted

技术标签:

【中文标题】Flutter Navigator.pop() 保持对话框部分可见,黑色阴影背景【英文标题】:Flutter Navigator.pop() keeps the Dialog Box partially visible with black shadow background 【发布时间】:2019-12-12 02:37:12 【问题描述】:

很抱歉解释太长,但我想我必须非常清楚这个话题。

过去几周我一直在讨论这个问题。我正在使用 flutter_bloc 包。

我有一个带有搜索框和列表视图的简单搜索页面(ProposalSearchPage)。 Listview 是根据分派KeywordsearchEvent 的搜索关键字构建的。点击设置图标会打开 ProposalSearchSetting 页面,这是一个对话框页面。

基于这种结构,我在集团中使用了两个事件。一个用于关键字搜索,另一个用于高级过滤器搜索。

应用过滤器后的预先搜索页面。在一个按钮内,我调度了 FilterSearchEvent 并使用 Navigation.pop(context) 返回到 ProposalSearchPage。 基于状态更改列表视图为这两个搜索呈现,但对于 Adavance 过滤器搜索,ProposalSearchSetting 对话框是部分可见的。那里的过滤器按钮是可点击的。当我单击后退箭头按钮时它会关闭。

我不知道为什么 Navigator.pop 将页面添加到堆栈而不是弹出堆栈。

  #PROPOSALSEARCH PAGE

class ProposalSearchPage extends StatefulWidget 
 final UserProfileBloc userProfileBloc;
 final MenuBloc menuBloc;
final String authToken;

  ProposalSearchPage(this.userProfileBloc, this.menuBloc, this.authToken)
  : assert(menuBloc != null),
    assert(userProfileBloc != null);

 @override
_ProposalSearchPageState createState() => _ProposalSearchPageState();


class _ProposalSearchPageState extends State<ProposalSearchPage> 
 UserProfileBloc get _userProfileBloc => widget.userProfileBloc;
 List filteredProposal = [];

String get _authToken => widget.authToken;

 MenuBloc get _menuBloc => widget.menuBloc;
ProposalSearchBloc _proposalSearchBloc;
String searchedKeyword = "";
int searchProposalPage = 1;

@override
void initState() 
_proposalSearchBloc =
    ProposalSearchBloc(proposalRepository: ProposalListingRepo());
_menuBloc.dispatch(MenuResponseFetchedEvent());
 super.initState();


@override
 void dispose() 
_proposalSearchBloc.dispose();
super.dispose();
  

@override
Widget build(BuildContext context) 
 return Scaffold(
  appBar: AppBar(
    backgroundColor: Color(0xff2b57ff),
    leading: IconButton(
      icon: Icon(Icons.chevron_left),
      onPressed: () 
        Navigator.of(context).pop();
      ,
    ),
    actions: <Widget>[
      IconButton(
          icon: new Icon(CupertinoIcons.gear_big),
          onPressed: () 
          /*  Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => ProposalSearchSetting(
                    proposalSearchBloc: _proposalSearchBloc,
                    menuBloc: _menuBloc,
                    userProfileBloc: _userProfileBloc,
                    context: context),
                fullscreenDialog: true,
              ),
            );*/

              showDialog<FilterProposalPost>(
                  context: context,
                  builder: (context) 
                    return ProposalSearchSetting(
                        proposalSearchBloc: _proposalSearchBloc,
                        menuBloc: _menuBloc,
                        userProfileBloc: _userProfileBloc,
                        context: context);
                  );
          ),
    ],
    title: Center(
      child: Container(
        width: 250.0,
        height: 35.0,
        decoration: BoxDecoration(
            color: Colors.black12,
            borderRadius: BorderRadius.all(Radius.circular(7.0))),
        child: CupertinoTextField(
          placeholder: 'search here.',
          style: TextStyle(
            color: Colors.white,
          ),
          onSubmitted: (keyword) 
            print(keyword);
            searchedKeyword = keyword;
            FilterProposalPost filterProposalPost =
                _buildSearchQueryParameter(keyword);
            // print(query);
            _proposalSearchBloc.proposalFilterPostParam(filterProposalPost);
          ,
        ),
      ),
    ),
  ),
  body: SearchListing(_proposalSearchBloc, _authToken),
);


  FilterProposalPost _buildSearchQueryParameter(String keyword) 
  return FilterProposalPost(
  ........
   );
  


  


   

 class SearchListing extends StatelessWidget 
 final ProposalSearchBloc _proposalSearchBloc;
 final String _authToken;

 SearchListing(this._proposalSearchBloc, this._authToken);

 @override
Widget build(BuildContext context) 
return BlocBuilder(
  bloc: _proposalSearchBloc,
  // ignore: missing_return
  builder: (context, state) 
    if (state is ProposalSearchFetchingState) 
      return Center(
        child: CircularProgressIndicator(
            valueColor: new AlwaysStoppedAnimation(Color(0xff2b57ff))),
      );
     else if (state is ProposalSearchFetchedState) 
      final filteredProposal = state.filteredProposal;
      print(filteredProposal.length.toString);
      return _buildSearchProposalList(filteredProposal);
    
  ,
);


 Widget _buildSearchProposalList(List searchedProposals) 
return ListView.builder(
    itemCount: searchedProposals.length + 1,
    itemBuilder: (context, position) 
      return position >= searchedProposals.length
          ? _buildLoaderListItem()
          : ProposalCardFactory(
              proposal: searchedProposals[position],
              authToken: _authToken,
            );
    );


Widget _buildLoaderListItem() 
return Center(
    child: CircularProgressIndicator(
        valueColor: new AlwaysStoppedAnimation(Color(0xff2b57ff))));
 
   






#ProposalSearchSettingPage

class ProposalSearchSetting extends StatefulWidget 
final UserProfileBloc userProfileBloc;
final ProposalSearchBloc proposalSearchBloc;
final MenuBloc menuBloc;
final BuildContext context;

final Function() notifyParent;

 ProposalSearchSetting(this.notifyParent,
  this.proposalSearchBloc,
  this.userProfileBloc,
  this.menuBloc,
  this.context);

   @override
  _ProposalSearchSettingState createState() => 
  _ProposalSearchSettingState();
   

  class _ProposalSearchSettingState extends State<ProposalSearchSetting>
  with SingleTickerProviderStateMixin 
  UserProfileBloc get _userProfileBloc => widget.userProfileBloc;

   ProposalSearchBloc get _proposalSearchBloc => widget.proposalSearchBloc;
   List<String> selectedOptions = [];
  String resultBy;

List<String> industries;
List<String> stages;
 List<String> locations;
List<String> languages;
List<String> countries;
List<String> regionsValue = [];

 MenuBloc get _menuBloc => widget.menuBloc;
 Animation<double> animation;
 AnimationController controller;
 double startingPoint;

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


@override
void dispose() 
_userProfileBloc.dispose();
 _proposalSearchBloc.dispose();
 super.dispose();
 

 @override
 Widget build(BuildContext context) 
 //double startingPoint = MediaQuery.of(context).size.height;
 return MaterialApp(
  theme: ThemeData(
      buttonTheme: ButtonThemeData(
          minWidth: 200.0,
          height: 40.0,
          buttonColor: Color(0xff2b57ff),
          textTheme: ButtonTextTheme.primary)),
  home: Scaffold(
    body: BlocBuilder(
      bloc: _menuBloc,
      // ignore: missing_return
      builder: (context, state) 
        if (state is MenuResponseFetchedState) 
          MenuListData _menuListData = state.menuListData;
          return Padding(
            padding: const EdgeInsets.only(top: 100.0),
            child: Center(
              child: Container(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    RaisedButton(
                      onPressed: () async 
                        resultBy = await showDialog(
                            context: context,
                            builder: (context) 
                              return ResultBySearchDialog(
                                  userProfileBloc: _userProfileBloc,
                                  menuListData: _menuListData,
                                  title: 'Result By:',
                                  options: _menuListData.displayBy.values
                                      .toList());
                            );
                      ,
                      color: Color(0xff2b57ff),
                      child: Text(
                        'RESULT BY',
                        style: TextStyle(fontFamily: 'MyRaidPro'),
                      ),
                    ),
                    SizedBox(
                      height: 20,
                    ),
                    RaisedButton(
                      onPressed: () async 
                        countries = await showDialog(
                            context: context,
                            builder: (context) 
                              return CountrySearchDialog(
                                  userProfileBloc: _userProfileBloc,
                                  menuListData: _menuListData,
                                  title: 'Select Countries',
                                  selectedOptions: selectedOptions,
                                  onSelectedOptionListChanged: (options) 
                                    selectedOptions = options;
                                    print(selectedOptions);
                                  );
                            );
                      ,
                      color: Color(0xff2b57ff),
                      child: Text(
                        'COUNTRY',
                        style: TextStyle(fontFamily: 'MyRaidPro'),
                      ),
                    ),
                    SizedBox(
                      height: 20,
                    ),
                    RaisedButton(
                      onPressed: () async 
                        industries = await showDialog(
                            context: context,
                            builder: (context) 
                              return IndustrySearchDialog(
                                  menuListData: _menuListData,
                                  title: 'Select Industries',
                                  options: _menuListData.industries.values
                                      .toList(),
                                  selectedOptions: selectedOptions,
                                  onSelectedOptionListChanged: (options) 
                                    selectedOptions = options;
                                    print(selectedOptions);
                                  );
                            );
                      ,
                      child: Text(
                        'INDUSTRIES',
                        style: TextStyle(fontFamily: 'MyRaidPro'),
                      ),
                    ),
                    SizedBox(
                      height: 20,
                    ),
                    RaisedButton(
                      onPressed: () async 
                        stages = await showDialog(
                            context: context,
                            builder: (context) 
                              return StageSearchDialog(
                                context: context,
                                  menuListData: _menuListData,
                                  title: 'Select Stages',
                                  options:
                                  _menuListData.stages.values.toList(),
                                  selectedOptions: selectedOptions,
                                  onSelectedOptionListChanged: (options) 
                                    selectedOptions = options;
                                    print(selectedOptions);
                                  );
                            );
                      ,
                      child: Text(
                        'STAGES',
                        style: TextStyle(fontFamily: 'MyRaidPro'),
                      ),
                    ),
                    SizedBox(
                      height: 20,
                    ),
                    RaisedButton(
                      onPressed: () async 
                        languages = await showDialog(
                            context: context,
                            builder: (context) 
                              return LanguageSearchDialog(
                                  menuListData: _menuListData,
                                  title: 'Select Languages',
                                  options: _menuListData.languages.values
                                      .toList(),
                                  selectedOptions: selectedOptions,
                                  onSelectedOptionListChanged: (options) 
                                    selectedOptions = options;
                                    print(selectedOptions);
                                  );
                            );
                      ,
                      child: Text(
                        'LANGUAGES',
                        style: TextStyle(fontFamily: 'MyRaidPro'),
                      ),
                    ),
                    SizedBox(
                      height: 20,
                    ),
                    RaisedButton(
                      onPressed: () async 
                        locations = await showDialog(
                            context: context,
                            builder: (context) 
                              return LocationSearchDialog(
                                  menuListData: _menuListData,
                                  title: 'Select Locations',
                                  options: _menuListData.locations.values
                                      .toList(),
                                  selectedOptions: selectedOptions,
                                  onSelectedOptionListChanged: (options) 
                                    selectedOptions = options;
                                    print(selectedOptions);
                                  );
                            );
                      ,
                      child: Text(
                        'LOCATIONS',
                        style: TextStyle(fontFamily: 'MyRaidPro'),
                      ),
                    ),
                    SizedBox(
                      height: 40,
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: <Widget>[
                        ButtonTheme(
                          textTheme: ButtonTextTheme.primary,
                          minWidth: 60,
                          child: RaisedButton(
                            onPressed: () 
                              Navigator.of(this.widget.context).pop();
                            ,
                            color: Color(0xff2b57ff),
                            child: Text(
                              'Cancel',
                              style: TextStyle(fontFamily: 'MyRaidPro'),
                            ),
                          ),
                        ),
                        ButtonTheme(
                          textTheme: ButtonTextTheme.primary,
                          minWidth: 60,
                          child: RaisedButton(
                            onPressed: () 


_proposalSearchBloc.dispatch(ProposalFilterFetchEvent(advanceFilter: 
 FilterProposalPost(......)));
                              Navigator.pop(context);

                              print(("value from dialog" +
                                  industries.toString()));

                              print(("value from dialog" +
                                  stages.toString()));

                              print(("value from dialog" +
                                  locations.toString()));

                              print(("value from dialog" +
                                  languages.toString()));
                            ,
                            color: Color(0xff2b57ff),
                            child: Text(
                              'Apply',
                              style: TextStyle(fontFamily: 'MyRaidPro'),
                            ),
                          ),
                        )
                      ],
                    )
                  ],
                ),
              ),
            ),
          );
        
      ,
    ),
  ),
);

#BLOC



class ProposalSearchBloc
extends Bloc<ProposalSearchEvent, ProposalSearchState> 
  final ProposalListingRepo proposalRepository;
List keywordSearchedProposalList = List();
List filteredProposalList = List();

ProposalSearchBloc(this.proposalRepository);

 void proposalFilterPostParam(FilterProposalPost filterProposalPost) 
 dispatch(ProposalSearchFetchEvent(filterProposalPost: filterProposalPost));
 



  @override
  ProposalSearchState get initialState => ProposalSearchFetchingState();

 @override
 Stream<ProposalSearchState> mapEventToState(event) async* 
try 
  var filteredProposal;
  print("proposal search even fired first time");
  if (event is ProposalSearchFetchEvent) 
    filteredProposal =
        await proposalRepository.filterProposal(event.filterProposalPost);
   else if (event is ProposalFilterFetchEvent) 
    print("filter event");

    filteredProposal =
        await proposalRepository.filterProposal(event.advanceFilter);
    filteredProposalList.addAll(filteredProposal);
    yield ProposalSearchFetchedState(filteredProposal: filteredProposal);
  
  catch (_) 
  //print(error.toString());
  yield ProposalSearchErrorState();
 
 

【问题讨论】:

【参考方案1】:

最后我能够解决问题。我只是忘了在我的集团中使用 try catch blok。这解决了从另一个页面(可能是对话框框)更改配置后重新加载上一个页面的大部分问题。我只需要对 Bloc 代码进行一些更改即可:

 @override
  Stream<ProposalSearchState> mapEventToState(event) async* 
    yield ProposalSearchFetchingState();
  if (event is ProposalSearchFetchEvent) 
   try 
    print("proposal search");
    filteredProposal =
        await proposalRepository.filterProposal(event.filterProposalPost);

    yield ProposalSearchFetchedState(
        searchedProposal: filteredProposal);
   catch (error) 
    print(error);
  

  if (event is ProposalFilterFetchEvent) 
    try 
      print("proposal filtered");
      filteredProposal =
          await proposalRepository.filterProposal(event.filterProposalPost);

      yield ProposalFilteredFetchedState(
          filteredProposal: filteredProposal);
     catch (error) 
      print(error.toString());
    
  

【讨论】:

以上是关于Flutter Navigator.pop() 保持对话框部分可见,黑色阴影背景的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 中的 navigator.pop(context) 之后显示小吃栏?

Flutter BLoC:构建()方法中 StreamBuilder 中的 Navigator.pop

Flutter - 从 AppBar 返回上一页不会刷新页面,使用 Navigator.pop(context)

Flutter Navigator.pop() 保持对话框部分可见,黑色阴影背景

Flutter Navigator.pop 再次运行小部件构建方法

调用 Navigator Pop 或 Push 时触发 Flutter Stream Builder