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() 保持对话框部分可见,黑色阴影背景