问题描述
我已经构建了一个 Scaffold 屏幕,主体中有一个 PageView 和一个底部导航栏。
我还为此页面构建了一个 Cubit + State 管理器。
当屏幕第一次打开时,我想要触发一个 API 调用。我还希望选择选项卡 1(在 PageView 和 bottomNavigationBar 上)。 当 API 返回响应时,我希望事件侦听器更新屏幕并选择选项卡 0。
这对bottomNavigationBar 很有效,但我在更新PageView 时遇到了问题。这是我的代码:
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _page = 1;
PageController _c;
double iconSize = 32;
bool forceCourseEnrolment = true;
@override
void initState() {
_c = new PageController(
initialPage: 1,keepPage: false,);
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocConsumer<HomeScreenCubit,HomeScreenState>(
listener: (context,state) {
debugPrint("listener received something");
if (state is DataRetrieved) {
state.enrolledCourses.length > 0
? forceCourseEnrolment = false
: forceCourseEnrolment = true;
state.enrolledCourses.length > 0 ? _page = 0 : _page = 1;
var hasClients = this._c.hasClients;
debugPrint("this._c.hasClients $hasClients");
// This prints: this._c.hasClients false
// Enabling this line:
// this._c.jumpToPage(_page);
// leads to:
// [ERROR:Flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: 'package:Flutter/src/widgets/scroll_controller.dart': Failed assertion: line 112 pos 12: '_positions.isNotEmpty': ScrollController not attached to any scroll views.
}
},builder: (context,state) {
if (state is HomeScreenInitial) {
context.bloc<HomeScreenCubit>().retrieveData();
return Scaffold(
body: SpinKitChasingDots(
color: COLOR_main_purple,size: 50.0,));
}
return Scaffold(
body: PageView(
controller: _c,onPageChanged: (newPage) {
setState(() {
this._page = newPage;
});
},physics: NeverScrollableScrollPhysics(),children: [
PurchasedCoursesTab(),ElearningTab(),MyPracticeTab(),ProfileTab(),],),bottomNavigationBar: SizedBox(
height: 80,child: Container(
decoration: Boxdecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(30),topLeft: Radius.circular(30)),BoxShadow: [
BoxShadow(
color: Colors.black38.withOpacity(0.1),spreadRadius: 0,blurRadius: 25),child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),topRight: Radius.circular(30.0),child: BottomNavigationBar(
currentIndex: _page,onTap: (index) {
if (forceCourseEnrolment == false) {
this._c.animatetoPage(index,duration: const Duration(milliseconds: 250),curve: Curves.easeInOut);
}
},type: BottomNavigationBarType.fixed,backgroundColor: Colors.white,items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
// title: Text(""),title: showIndicator(_page == 0),icon: Container(
width: iconSize,height: iconSize,child: SvgPicture.asset('assets/images/ic_run.svg',color: _page == 0
? COLOR_main_purple
: forceCourseEnrolment == false
? Colors.black
: COLOR_main_text_grey_with_opacity),)),BottomNavigationBarItem(
title: showIndicator(_page == 1),child: SvgPicture.asset(
'assets/images/ic_e_learning.svg',color: _page == 1
? COLOR_main_purple
: Colors.black),BottomNavigationBarItem(
title: showIndicator(_page == 2),child: SvgPicture.asset(
'assets/images/ic_journal.svg',color: _page == 2
? COLOR_main_purple
: forceCourseEnrolment == false
? Colors.black
: COLOR_main_text_grey_with_opacity),BottomNavigationBarItem(
title: showIndicator(_page == 3),// title: Text(_page == 3 ? "•" : "",style: TextStyle(
// color: COLOR_main_purple,fontSize: 24.0)),child: SvgPicture.asset(
'assets/images/ic_gamification.svg',color: _page == 3
? COLOR_main_purple
: forceCourseEnrolment == false
? Colors.black
: COLOR_main_text_grey_with_opacity),));
});
}
}
当我尝试在 BlocConsumer 的侦听器中更改页面时遇到的错误:
[错误:Flutter/lib/ui/ui_dart_state.cc(177)] 未处理的异常: 'package:Flutter/src/widgets/scroll_controller.dart': 失败 断言:第 112 行 pos 12:'_positions.isNotEmpty':ScrollController 未附加到任何滚动视图。
解决方法
发现我可以通过向侦听器添加以下内容来使其工作:
if (state is DataRetrieved) {
state.enrolledCourses.length > 0
? forceCourseEnrolment = false
: forceCourseEnrolment = true;
state.enrolledCourses.length > 0 ? _page = 0 : _page = 1;
Future.delayed(Duration(milliseconds: 50),() {
if (this._c.hasClients) {
this._c.jumpToPage(_page);
}
});
}
我发现这是一个丑陋的解决方案,所以我不会将其标记为答案。如果您知道处理此问题的更好方法,请告诉我。