@@ -181,6 +181,12 @@ | |||
"packageUri": "lib/", | |||
"languageVersion": "2.0" | |||
}, | |||
{ | |||
"name": "event_bus", | |||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/event_bus-1.1.1", | |||
"packageUri": "lib/", | |||
"languageVersion": "2.0" | |||
}, | |||
{ | |||
"name": "file", | |||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/file-5.2.1", | |||
@@ -463,6 +469,12 @@ | |||
"packageUri": "lib/", | |||
"languageVersion": "2.2" | |||
}, | |||
{ | |||
"name": "pull_to_refresh", | |||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/pull_to_refresh-1.6.1", | |||
"packageUri": "lib/", | |||
"languageVersion": "2.1" | |||
}, | |||
{ | |||
"name": "quiver", | |||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/quiver-2.0.5", | |||
@@ -668,7 +680,7 @@ | |||
"languageVersion": "2.1" | |||
} | |||
], | |||
"generated": "2020-09-04T06:52:20.100476Z", | |||
"generated": "2020-09-07T03:45:53.992384Z", | |||
"generator": "pub", | |||
"generatorVersion": "2.7.2" | |||
} |
@@ -1,11 +1,20 @@ | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/pages/main_page/main_page_bloc.dart'; | |||
import 'package:zhiying_base_widget/pages/main_page/main_page_notifier.dart'; | |||
import 'package:zhiying_base_widget/pages/main_page/main_page_sk.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:provider/provider.dart'; | |||
import 'package:zhiying_comm/util/base_bloc.dart'; | |||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||
class MainPage extends StatefulWidget { | |||
MainPage({Key key}) : super(key: key); | |||
final Map<String, dynamic> data; | |||
MainPage( | |||
this.data, { | |||
Key key, | |||
}) : super(key: key); | |||
@override | |||
_MainPageState createState() => _MainPageState(); | |||
@@ -18,23 +27,49 @@ class _MainPageState extends State<MainPage> { | |||
backgroundColor: Color(0xfff9f9f9), | |||
body: ChangeNotifierProvider( | |||
create: (context) => MainPageNotifier(), | |||
child: MainPageContainer(), | |||
child: BlocProvider<MainPageBloc>( | |||
bloc: MainPageBloc(), | |||
child: _MainPageContainer(widget.data), | |||
), | |||
), | |||
); | |||
} | |||
} | |||
class MainPageContainer extends StatefulWidget { | |||
MainPageContainer({Key key}) : super(key: key); | |||
class _MainPageContainer extends StatefulWidget { | |||
final Map<String, dynamic> data; | |||
_MainPageContainer(this.data, {Key key}) : super(key: key); | |||
@override | |||
_MainPageContainerState createState() => _MainPageContainerState(); | |||
} | |||
class _MainPageContainerState extends State<MainPageContainer> { | |||
class _MainPageContainerState extends State<_MainPageContainer> { | |||
WidgetType _type = WidgetType.normal; | |||
bool _isEnded = false; | |||
ScrollController _controller = ScrollController(); | |||
MainPageBloc _bloc; | |||
List<String> items = ["1", "2", "3", "4", "5", "6", "7", "8"]; | |||
RefreshController _refreshController = | |||
RefreshController(initialRefresh: false); | |||
void _onRefresh() async { | |||
// monitor network fetch | |||
await Future.delayed(Duration(milliseconds: 1000)); | |||
// if failed,use refreshFailed() | |||
_refreshController.refreshCompleted(); | |||
} | |||
void _onLoading() async { | |||
// monitor network fetch | |||
await Future.delayed(Duration(milliseconds: 1000)); | |||
// if failed,use loadFailed(),if no data return,use LoadNodata() | |||
items.add((items.length + 1).toString()); | |||
if (mounted) setState(() {}); | |||
_refreshController.loadComplete(); | |||
} | |||
@override | |||
void dispose() { | |||
@@ -44,6 +79,7 @@ class _MainPageContainerState extends State<MainPageContainer> { | |||
@override | |||
void initState() { | |||
_bloc = BlocProvider.of<MainPageBloc>(context); | |||
_reload(); | |||
_controller.addListener(() { | |||
// print('${_controller.offset} ${_controller.position.maxScrollExtent}'); | |||
@@ -65,11 +101,16 @@ class _MainPageContainerState extends State<MainPageContainer> { | |||
setState(() { | |||
_type = WidgetType.skeleton; | |||
}); | |||
Future.delayed(Duration(seconds: 3), () { | |||
setState(() { | |||
_type = WidgetType.normal; | |||
}); | |||
}); | |||
WidgetModel model = WidgetModel.fromJson(widget.data); | |||
if ((model?.components?.length ?? 0) > 0) { | |||
_bloc.loadData(model.components.map((item) => item.modId).toList()); | |||
} | |||
// Future.delayed(Duration(seconds: 3), () { | |||
// setState(() { | |||
// _type = WidgetType.normal; | |||
// }); | |||
// }); | |||
} | |||
List<Widget> _createContent(BuildContext context) { | |||
@@ -94,11 +135,47 @@ class _MainPageContainerState extends State<MainPageContainer> { | |||
@override | |||
Widget build(BuildContext context) { | |||
return SafeArea( | |||
child: CustomScrollView( | |||
controller: _controller, | |||
slivers: _createContent(context), | |||
), | |||
return StreamBuilder<List<List<Map<String, dynamic>>>>( | |||
stream: _bloc.outData, | |||
builder: (BuildContext context, AsyncSnapshot snapshot) { | |||
if (snapshot.data == null) { | |||
return MainPageSkeleton(); | |||
} | |||
_type = WidgetType.normal; | |||
return SmartRefresher( | |||
enablePullDown: true, | |||
enablePullUp: true, | |||
header: WaterDropHeader(), | |||
footer: CustomFooter( | |||
builder: (BuildContext context, LoadStatus mode) { | |||
Widget body; | |||
if (mode == LoadStatus.idle) { | |||
body = Text("上拉加载"); | |||
} else if (mode == LoadStatus.loading) { | |||
body = CupertinoActivityIndicator(); | |||
} else if (mode == LoadStatus.failed) { | |||
body = Text("加载失败!点击重试!"); | |||
} else if (mode == LoadStatus.canLoading) { | |||
body = Text("松手,加载更多!"); | |||
} else { | |||
body = Text("没有更多数据了!"); | |||
} | |||
return Container( | |||
height: 55.0, | |||
child: Center(child: body), | |||
); | |||
}, | |||
), | |||
controller: _refreshController, | |||
onRefresh: _onRefresh, | |||
onLoading: _onLoading, | |||
child: CustomScrollView( | |||
controller: _controller, | |||
slivers: _createContent(context), | |||
), | |||
); | |||
}, | |||
); | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
import 'dart:async'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:zhiying_comm/util/base_bloc.dart'; | |||
class MainPageBloc extends BlocBase { | |||
List<List<Map<String, dynamic>>> _mains = List(); | |||
StreamController<List<List<Map<String, dynamic>>>> _mainController = | |||
StreamController<List<List<Map<String, dynamic>>>>(); | |||
Stream<List<List<Map<String, dynamic>>>> get outData => | |||
_mainController.stream; | |||
@override | |||
void dispose() { | |||
_mainController.close(); | |||
_mainController = null; | |||
} | |||
void loadData(List<int> ids) { | |||
NetUtil.request('/api/v1/mod', | |||
method: NetMethod.POST, | |||
params: Map<String, dynamic>.from({'ids': ids}), onSuccess: (data) { | |||
Map<String, dynamic> datas = data; | |||
List<List<Map<String, dynamic>>> result = List(); | |||
for (int id in ids) { | |||
if (datas.containsKey(id.toString())) { | |||
result.add(List<Map<String, dynamic>>.from(datas[id.toString()])); | |||
} else { | |||
result.add(List<Map<String, dynamic>>()); | |||
} | |||
} | |||
_mains = result; | |||
_mainController.add(_mains); | |||
}); | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
// ignore: must_be_immutable | |||
class MainPageSkeleton extends StatelessWidget { | |||
ScrollController _controller; | |||
MainPageSkeleton({Key key}) : super(key: key) { | |||
_controller = ScrollController(); | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
return SafeArea( | |||
child: CustomScrollView( | |||
controller: _controller, | |||
slivers: _createContent(context), | |||
), | |||
); | |||
} | |||
List<Widget> _createContent(BuildContext context) { | |||
List<Widget> list = List(); | |||
list.addAll(WidgetFactory.create('index_carousel', | |||
type: WidgetType.skeleton, | |||
isSliver: true, | |||
model: Map<String, dynamic>.from({'aaaaa': 'bbbb'}))); | |||
list.addAll(WidgetFactory.create('index_recommend_list', | |||
type: WidgetType.skeleton, isSliver: true)); | |||
return list; | |||
} | |||
} |
@@ -14,7 +14,7 @@ class BaseWidgetRegister { | |||
// 注册页面 | |||
static void registPage() { | |||
PageFactory.regist('homePage', (model) => HomePage()); | |||
PageFactory.regist('index', (model) => MainPage()); | |||
PageFactory.regist('index', (model) => MainPage(model)); | |||
} | |||
// 注册控件 | |||
@@ -4,54 +4,40 @@ import 'package:zhiying_base_widget/widgets/home_goods/home_goods_header.dart'; | |||
import 'package:zhiying_base_widget/widgets/home_goods/skeleton/home_goods_header_sk.dart'; | |||
import 'package:zhiying_base_widget/widgets/home_goods/skeleton/home_goods_sk.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'package:event_bus/event_bus.dart'; | |||
class GoodsListCreater extends WidgetCreater { | |||
@override | |||
List<Widget> createWidgets(Map<String, dynamic> model) { | |||
TabController controller = | |||
TabController(initialIndex: 0, length: 6, vsync: ScrollableState()); | |||
EventBus eventBus = EventBus(); | |||
return [ | |||
_createHeader(controller), | |||
_createBody(controller), | |||
SliverPersistentHeader( | |||
pinned: true, | |||
floating: false, | |||
delegate: HomeGoodsDelegate(), | |||
), | |||
SliverToBoxAdapter( | |||
child: HomeGoods(), | |||
), | |||
]; | |||
} | |||
@override | |||
List<Widget> createSkeleton(Map<String, dynamic> model) { | |||
return [ | |||
_createHeaderSkeleton(), | |||
_createBodySkeleton(), | |||
]; | |||
} | |||
Widget _createHeader(TabController controller) { | |||
return SliverPersistentHeader( | |||
pinned: true, | |||
floating: false, | |||
delegate: HomeGoodsDelegate(controller), | |||
); | |||
} | |||
Widget _createHeaderSkeleton() { | |||
return SliverPersistentHeader( | |||
SliverPersistentHeader( | |||
pinned: true, | |||
floating: false, | |||
delegate: HomeGoodsHeaderSkeletonDelegate(), | |||
); | |||
} | |||
Widget _createBody(TabController controller) { | |||
return SliverToBoxAdapter( | |||
child: HomeGoods(), | |||
); | |||
} | |||
Widget _createBodySkeleton() { | |||
return SliverToBoxAdapter( | |||
), | |||
SliverToBoxAdapter( | |||
child: HomeGoodsSkeleton(), | |||
); | |||
), | |||
]; | |||
} | |||
@override | |||
bool isSliverChild() { | |||
return true; | |||
@@ -1,9 +1,6 @@ | |||
import 'package:flutter/material.dart'; | |||
class HomeGoodsDelegate extends SliverPersistentHeaderDelegate { | |||
final TabController controller; | |||
HomeGoodsDelegate(this.controller); | |||
@override | |||
Widget build( | |||
@@ -13,7 +10,7 @@ class HomeGoodsDelegate extends SliverPersistentHeaderDelegate { | |||
color: Colors.red, | |||
alignment: Alignment.center, | |||
child: TabBar( | |||
controller: controller, | |||
controller: TabController(initialIndex: 0, length: 6, vsync: ScrollableState()), | |||
isScrollable: true, | |||
tabs: <Widget>[ | |||
Tab(icon: Icon(Icons.local_florist)), | |||
@@ -28,10 +25,10 @@ class HomeGoodsDelegate extends SliverPersistentHeaderDelegate { | |||
} | |||
@override | |||
double get maxExtent => 60.0; | |||
double get maxExtent => 64.0; | |||
@override | |||
double get minExtent => 60.0; | |||
double get minExtent => 64.0; | |||
@override | |||
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => | |||
@@ -16,6 +16,8 @@ dependencies: | |||
provider: ^4.0.0 | |||
bloc: ^4.0.0 | |||
flutter_bloc: ^4.0.1 | |||
event_bus: ^1.1.1 | |||
pull_to_refresh: ^1.6.1 | |||
dev_dependencies: | |||
flutter_test: | |||