From ac676829189e39d0711c87424062027d755318ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E5=A4=A9?= Date: Sun, 23 Jul 2023 16:28:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90Application-Category=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/application_controller.dart | 2 +- lib/modules/category/category_binding.dart | 5 +- lib/modules/category/category_controller.dart | 71 +++++++++ lib/modules/category/category_page.dart | 5 +- lib/modules/category/category_state.dart | 7 + lib/modules/category/widgets/news_item.dart | 142 ++++++++++++++++++ .../category/widgets/news_page_list.dart | 52 +++++++ 7 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 lib/modules/category/category_state.dart create mode 100644 lib/modules/category/widgets/news_item.dart create mode 100644 lib/modules/category/widgets/news_page_list.dart diff --git a/lib/modules/application/application_controller.dart b/lib/modules/application/application_controller.dart index f983819..317b9d5 100644 --- a/lib/modules/application/application_controller.dart +++ b/lib/modules/application/application_controller.dart @@ -51,7 +51,7 @@ class ApplicationController extends GetxController { super.onInit(); // 准备静态数据 作为tab - tabTitles = ['Welcome', 'Cagegory', 'Bookmarks', 'Account']; + tabTitles = ['Welcome', 'Category', 'Bookmarks', 'Account']; bottomTabs = [ BottomNavigationBarItem( icon: Icon( diff --git a/lib/modules/category/category_binding.dart b/lib/modules/category/category_binding.dart index 487dd98..a53d03f 100644 --- a/lib/modules/category/category_binding.dart +++ b/lib/modules/category/category_binding.dart @@ -1,10 +1,13 @@ import 'package:get/get.dart'; +import 'package:news_getx/data/repository/news_repository.dart'; import 'category_controller.dart'; class CategoryBinding extends Bindings { @override void dependencies() { - Get.lazyPut(() => CategoryController()); + Get.lazyPut(() => CategoryController( + newsRepository: NewsRepository() + )); } } diff --git a/lib/modules/category/category_controller.dart b/lib/modules/category/category_controller.dart index 22c7ccc..b643781 100644 --- a/lib/modules/category/category_controller.dart +++ b/lib/modules/category/category_controller.dart @@ -1,5 +1,76 @@ import 'package:get/get.dart'; +import 'package:news_getx/data/model/news.dart'; +import 'package:news_getx/data/repository/news_repository.dart'; +import 'package:news_getx/modules/category/category_state.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; class CategoryController extends GetxController { + NewsRepository newsRepository; + CategoryController({required this.newsRepository}); + + /// UI 组件 + final RefreshController refreshController = RefreshController( + initialRefresh: true, + ); + + /// 响应式成员变量 + final state = CategoryState(); + + /// 成员变量 + String categoryCode = ''; + int curPage = 1; + int pageSize = 20; + int total = 20; + + /// 事件 + void onRefresh() { + fetchNewsList(isRefresh: true).then((_) { + refreshController.refreshCompleted(resetFooterState: true); + }).catchError((_) { + refreshController.refreshFailed(); + }); + } + + void onLoading() { + if (state.newsList.length < total) { + fetchNewsList().then((_) { + refreshController.loadComplete(); + }).catchError((_) { + refreshController.loadFailed(); + }); + } else { + refreshController.loadNoData(); + } + } + + /// 方法 + + // 拉取数据 + Future fetchNewsList({bool isRefresh = false}) async { + var result = await newsRepository.newsPageList( + params: NewsPageListRequest( + categoryCode: categoryCode, + pageNum: curPage + 1, + pageSize: pageSize, + ), + ); + + if (isRefresh) { + curPage = 1; + total = result.counts!; + state.newsList.clear(); + } else { + curPage++; + } + + state.newsList.addAll(result.items!); + } + + ///dispose 释放内存 + @override + void dispose() { + super.dispose(); + refreshController.dispose(); + } } diff --git a/lib/modules/category/category_page.dart b/lib/modules/category/category_page.dart index 06b9867..c75b378 100644 --- a/lib/modules/category/category_page.dart +++ b/lib/modules/category/category_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:news_getx/modules/category/widgets/news_page_list.dart'; import 'category_controller.dart'; @@ -8,6 +9,8 @@ class CategoryPage extends GetView { @override Widget build(BuildContext context) { - return Text('Categories'); + return Scaffold( + body: NewsPageList(), + ); } } diff --git a/lib/modules/category/category_state.dart b/lib/modules/category/category_state.dart new file mode 100644 index 0000000..de730bc --- /dev/null +++ b/lib/modules/category/category_state.dart @@ -0,0 +1,7 @@ +import 'package:get/get.dart'; +import 'package:news_getx/data/model/news.dart'; + +class CategoryState { + // 分类 + RxList newsList = [].obs; +} diff --git a/lib/modules/category/widgets/news_item.dart b/lib/modules/category/widgets/news_item.dart new file mode 100644 index 0000000..15eeace --- /dev/null +++ b/lib/modules/category/widgets/news_item.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:news_getx/data/model/news.dart'; +import 'package:news_getx/modules/widgets/image.dart'; +import 'package:news_getx/theme/app_colors.dart'; +import 'package:news_getx/utils/date.dart'; + +class NewsListItem extends StatelessWidget { + const NewsListItem({super.key, required this.newsItem}); + + final NewsItem newsItem; + + @override + Widget build(BuildContext context) { + return Container( + height: 161.h, + padding: EdgeInsets.all(20.w), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 左侧图 + InkWell( + onTap: () { + // 到详情页 + }, + child: SizedBox( + width: 121.w, + height: 121.w, + child: netImageCached( + newsItem.thumbnail ?? "", + width: 121.w, + height: 121.w, + ), + ), + ), + + // 右侧内容 + SizedBox( + width: 194.w, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 作者 + Container( + margin: EdgeInsets.all(0), + child: Text( + newsItem.author ?? '', + style: TextStyle( + fontFamily: 'Avenir', + fontWeight: FontWeight.normal, + color: AppColors.thirdElementText, + fontSize: 14.sp, + ), + ), + ), + // 标题 + InkWell( + onTap: () { + // 到详情页 + }, + child: Container( + margin: EdgeInsets.only(top: 10.h), + child: Text( + newsItem.title ?? '', + overflow: TextOverflow.clip, + maxLines: 3, + style: TextStyle( + fontFamily: 'Montserrat', + fontWeight: FontWeight.w500, + color: AppColors.primaryText, + fontSize: 16.sp, + ), + ), + ), + ), + + Spacer(), + // 一行 3 列 + Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ConstrainedBox( + // 分类 + constraints: BoxConstraints(maxWidth: 60.w), + child: Text( + newsItem.category ?? "", + style: TextStyle( + fontFamily: 'Avenir', + fontWeight: FontWeight.normal, + color: AppColors.secondaryElementText, + fontSize: 14.sp, + height: 1, + ), + overflow: TextOverflow.clip, + maxLines: 1, + ), + ), + // 添加时间 + Container( + width: 15.w, + ), + ConstrainedBox( + constraints: BoxConstraints(maxWidth: 100.w), + child: Text( + '• ${timeLineFormat(newsItem.addtime ?? DateTime(0))}', + style: TextStyle( + fontFamily: 'Avenir', + fontWeight: FontWeight.normal, + color: AppColors.thirdElementText, + fontSize: 14.sp, + height: 1, + ), + overflow: TextOverflow.clip, + maxLines: 1, + ), + ), + // 占满剩余空间 + Spacer(), + // 更多 + InkWell( + child: Icon( + Icons.more_horiz, + color: AppColors.primaryText, + size: 24, + ), + onTap: () { + print('查看更多...'); + }, + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/modules/category/widgets/news_page_list.dart b/lib/modules/category/widgets/news_page_list.dart new file mode 100644 index 0000000..4099e91 --- /dev/null +++ b/lib/modules/category/widgets/news_page_list.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:news_getx/modules/category/category_controller.dart'; +import 'package:news_getx/modules/category/widgets/news_item.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +class NewsPageList extends StatefulWidget { + const NewsPageList({Key? key}) : super(key: key); + + @override + State createState() => _NewsPageListState(); +} + +class _NewsPageListState extends State + with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + final controller = Get.find(); + + @override + Widget build(BuildContext context) { + super.build(context); + return GetX( + init: controller, + builder: (controller) { + return SmartRefresher( + controller: controller.refreshController, + enablePullUp: true, + onRefresh: controller.onRefresh, + onLoading: controller.onLoading, + child: CustomScrollView( + slivers: [ + SliverPadding( + padding: EdgeInsets.symmetric(vertical: 0.w, horizontal: 0.h), + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + var item = controller.state.newsList[index]; + return NewsListItem(newsItem: item); + }, + childCount: controller.state.newsList.length, + ), + ), + ), + ], + ), + ); + }); + } +}