From 8df5fbf92b47fa89a767ee8c5d97bcbd74e7b541 Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Fri, 17 May 2024 01:00:57 +0800 Subject: [PATCH] feat:单元列表页由于ios嵌套滑动不生效,调整方案使用指示器标识,并支持指示器滑动以及点击联动翻页 --- lib/pages/home/bloc.dart | 1 - lib/pages/home/view.dart | 5 ----- lib/pages/practice/bloc/topic_picture_bloc.dart | 3 +-- lib/pages/reading/bloc/reading_bloc.dart | 2 +- lib/pages/section/bloc/section_bloc.dart | 32 ++++++++++++++++++++++++++++++-- lib/pages/section/section_page.dart | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------ 6 files changed, 159 insertions(+), 137 deletions(-) diff --git a/lib/pages/home/bloc.dart b/lib/pages/home/bloc.dart index 325ea27..7d455df 100644 --- a/lib/pages/home/bloc.dart +++ b/lib/pages/home/bloc.dart @@ -16,7 +16,6 @@ class HomeBloc extends Bloc { void _init(InitEvent event, Emitter emit) async { await _checkUpdate(emit); - debugPrint('WQF ModuleSelectBloc _init'); } Future _checkUpdate(Emitter emit) async { diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index 7f9b843..12632b3 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -13,7 +13,6 @@ import 'package:wow_english/pages/user/bloc/user_bloc.dart'; import '../../common/core/user_util.dart'; import '../../common/dialogs/show_dialog.dart'; -import '../../utils/log_util.dart'; import 'bloc.dart'; import 'event.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -38,11 +37,9 @@ class _HomePageView extends StatelessWidget { Widget build(BuildContext context) { return MultiBlocListener(listeners: [ BlocListener(listener: (context, state) { - debugPrint('WQF ModuleSelectPage BlocListener state: $state'); }), BlocListener( listener: (context, state) { - Log.d("WQF HomePage listener state: $state"); if (state is UpdateDialogState) { _showUpdateDialog(context, state.forceUpdate, state.appVersionEntity); } @@ -97,8 +94,6 @@ class _HomePageView extends StatelessWidget { Expanded( child: BlocBuilder( builder: (context, userState) { - debugPrint( - 'WQF ModuleSelectPage BlocBuilder state: $userState'); return GestureDetector( onTap: () { _checkPermission(() { diff --git a/lib/pages/practice/bloc/topic_picture_bloc.dart b/lib/pages/practice/bloc/topic_picture_bloc.dart index 5c4e7ee..e9fbda3 100644 --- a/lib/pages/practice/bloc/topic_picture_bloc.dart +++ b/lib/pages/practice/bloc/topic_picture_bloc.dart @@ -103,7 +103,7 @@ class TopicPictureBloc extends BaseSectionBloc { - PageController _pageController; PageController get pageController => _pageController; @@ -30,6 +32,10 @@ class SectionBloc extends Bloc { ScrollController get listController => _listController; + ScrollController _indicatorSrollController; + + ScrollController get indicatorSrollController => _indicatorSrollController; + CourseUnitEntity _courseUnitEntity; CourseUnitEntity get courseUnitEntity => _courseUnitEntity; @@ -45,7 +51,7 @@ class SectionBloc extends Bloc { CourseProcessEntity? get processEntity => _processEntity; SectionBloc(this._courseUnitEntity, this._currentPage, this._pageController, - this._listController) + this._listController, this._indicatorSrollController) : super(LessonInitial()) { on(_requestSectionsData); on(_requestEndClass); @@ -121,6 +127,28 @@ class SectionBloc extends Bloc { void _pageControllerChange( CurrentUnitIndexChangeEvent event, Emitter emitter) async { _currentPage = event.unitIndex; + double indicatorWidth = 30.0.w; // 指示器宽度 + + // 计算选中项的偏移量 + double offset = _currentPage * indicatorWidth - + (_indicatorSrollController.position.viewportDimension - + indicatorWidth) / + 2; + + // 确保偏移量在合理范围内 + if (offset < 0) { + offset = 0; + } else if (offset > + unlockPageCount() * indicatorWidth - + _indicatorSrollController.position.viewportDimension) { + offset = unlockPageCount() * indicatorWidth - + _indicatorSrollController.position.viewportDimension; + } + _indicatorSrollController.animateTo( + offset, + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + ); emitter(CurrentPageIndexState()); } diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart index 1db876e..b415193 100644 --- a/lib/pages/section/section_page.dart +++ b/lib/pages/section/section_page.dart @@ -33,8 +33,14 @@ class SectionPage extends StatelessWidget { ?.indexWhere((element) => element.id == courseUnitId) ?? 0; return BlocProvider( - create: (context) => SectionBloc(courseUnitEntity, initialPage, - PageController(initialPage: initialPage), ScrollController()), + create: (context) => SectionBloc( + courseUnitEntity, + initialPage, + PageController(initialPage: initialPage), + ScrollController(), + ScrollController()) + //为了触发指示器进入后计算位置 + ..add(CurrentUnitIndexChangeEvent(initialPage)), child: _SectionPageView(context), ); } @@ -148,76 +154,79 @@ class _SectionPageView extends StatelessWidget { title: bloc.getCourseUnitDetail().name, courseModuleCode: bloc.courseUnitEntity.courseModuleCode), Expanded( - child: Container( - color: Colors.blue, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 10.w), - // child: OverflowBox( - child: NestedPageView.builder( - itemCount: bloc.unlockPageCount(), - controller: bloc.pageController, - onPageChanged: (int index) { - bloc.add(CurrentUnitIndexChangeEvent(index)); - }, - itemBuilder: (context, index) { - // return ScrollConfiguration( - // ///去掉 Android 上默认的边缘拖拽效果 - // behavior: ScrollConfiguration.of(context) - // .copyWith(overscroll: false), - // child: _itemTransCard( - // bloc.getCourseUnitDetail(pageIndex: index), - // index, - // context), - // ); - return _itemTransCard( - bloc.getCourseUnitDetail(pageIndex: index), - index, - context); - }), - // ), // 设置外部padding, - ) - ) - ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: NestedPageView.builder( + itemCount: bloc.unlockPageCount(), + controller: bloc.pageController, + onPageChanged: (int index) { + bloc.add(CurrentUnitIndexChangeEvent(index)); + }, + itemBuilder: (context, index) { + return ScrollConfiguration( + ///去掉 Android 上默认的边缘拖拽效果 + behavior: ScrollConfiguration.of(context) + .copyWith(overscroll: false), + child: _itemTransCard( + bloc.getCourseUnitDetail(pageIndex: index), + index, + context), + ); + }), + )), SafeArea( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 13.w), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - height: 47.h, - width: 80.w, - ), - Container( - decoration: BoxDecoration( - color: CourseModuleModel( - bloc.courseUnitEntity.courseModuleCode ?? - 'Phase-1') - .color, - borderRadius: BorderRadius.circular(14.5.r), - ), - padding: EdgeInsets.symmetric( - vertical: 8.h, horizontal: 24.w), - child: Text( - '${bloc.currentPage + 1}/${bloc.unlockPageCount()}', - style: TextStyle( - color: Colors.white, fontSize: 12.sp), - ), - ), - Image.asset( - CourseModuleModel( - bloc.courseUnitEntity.courseModuleCode ?? - 'Phase-1') - .courseModuleLogo - .assetPng, - height: 47.h, - width: 80.w, - // color: Colors.red, - ), - ], - ), - ), - ) + child: SizedBox( + width: 210.w, + height: 40.h, + // child: OverflowBox( + // maxWidth: 300, // 允许内容超出容器宽度 + child: ListView.builder( + controller: bloc.indicatorSrollController, + scrollDirection: Axis.horizontal, + itemCount: bloc.unlockPageCount(), + itemBuilder: (context, index) { + bool isSelected = index == bloc.currentPage; + // 计算透明度,使得当前页的指示器不透明,两侧逐渐透明 + double opacity = 0.25 + + (1 - ((bloc.currentPage - index).abs() / 2)) * + 0.5; + // 限制透明度在 0.5 到 1.0 之间 + opacity = opacity.clamp(0.25, 1.0); + return GestureDetector( + onTap: () => bloc.pageController.animateToPage( + index, + duration: const Duration(milliseconds: 60), + curve: Curves.ease), + child: SizedBox( + width: 30.0.w, + height: 30.0.h, + child: Padding( + padding: + EdgeInsets.all(isSelected ? 0.w : 5.w), + child: Opacity( + opacity: opacity, + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: isSelected + ? Colors.blue + : Colors.grey, + shape: BoxShape.circle, + ), + child: Text("${index + 1}", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: + isSelected ? 12.sp : 8.sp)), + ), + ), + ), + ), + ); + })), + ), + // ) ], ), ), @@ -252,62 +261,54 @@ Widget _itemTransCard( ), ); } else { - return - Padding(padding: EdgeInsets.symmetric( - vertical: 28.h), - child: Container( - color: Colors.red, - margin: EdgeInsets.symmetric(vertical: 10.h), - child: NestedListView.builder( - itemCount: bloc.courseSectionDatasMap[courseUnitDetail.id]?.length ?? 0, - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext context, int index) { - CourseSectionEntity sectionData = courseSectionEntities[index]; - if (sectionData.courseType == SectionType.bouns.value) { - //彩蛋 - return GestureDetector( - onTap: () { - if (!UserUtil.isLogined()) { - pushNamed(AppRouteName.login); - return; - } - if (sectionData.lock == true) { - showToast('当前课程暂未解锁'); - return; - } + return NestedListView.builder( + itemCount: bloc.courseSectionDatasMap[courseUnitDetail.id]?.length ?? 0, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + CourseSectionEntity sectionData = courseSectionEntities[index]; + if (sectionData.courseType == SectionType.bouns.value) { + //彩蛋 + return GestureDetector( + onTap: () { + if (!UserUtil.isLogined()) { + pushNamed(AppRouteName.login); + return; + } + if (sectionData.lock == true) { + showToast('当前课程暂未解锁'); + return; + } - ///进入课堂 - bloc.add(RequestEnterClassEvent( - sectionData.id.toString(), sectionData.courseType)); - }, - child: SectionBoundsItem( - imageUrl: sectionData.coverUrl, - ), - ); - } else { - return GestureDetector( - onTap: () { - if (!UserUtil.isLogined()) { - pushNamed(AppRouteName.login); - return; - } - if (sectionData.lock == true) { - showToast('当前课程暂未解锁'); - return; - } + ///进入课堂 + bloc.add(RequestEnterClassEvent( + sectionData.id.toString(), sectionData.courseType)); + }, + child: SectionBoundsItem( + imageUrl: sectionData.coverUrl, + ), + ); + } else { + return GestureDetector( + onTap: () { + if (!UserUtil.isLogined()) { + pushNamed(AppRouteName.login); + return; + } + if (sectionData.lock == true) { + showToast('当前课程暂未解锁'); + return; + } - ///进入课堂 - bloc.add(RequestEnterClassEvent( - sectionData.id.toString(), sectionData.courseType)); - }, - child: SectionItem( - courseModuleId: bloc.courseUnitEntity.courseModuleCode, - lessons: sectionData, - ), - ); - } - }), - ), - ); + ///进入课堂 + bloc.add(RequestEnterClassEvent( + sectionData.id.toString(), sectionData.courseType)); + }, + child: SectionItem( + courseModuleId: bloc.courseUnitEntity.courseModuleCode, + lessons: sectionData, + ), + ); + } + }); } } -- libgit2 0.22.2