基础组件库
 
 
 
 
 

287 lines
8.5 KiB

  1. import 'package:flutter/cupertino.dart';
  2. import 'package:pull_to_refresh/pull_to_refresh.dart';
  3. import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart';
  4. import 'package:zhiying_base_widget/widgets/refresh/refresh_header/refresh_header.dart';
  5. import 'package:zhiying_comm/zhiying_comm.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:provider/provider.dart';
  8. import 'package:zhiying_comm/util/custom_sliver_persistent_header_delegate.dart';
  9. import 'package:flutter_bloc/flutter_bloc.dart';
  10. import 'bloc/custom_page_bloc.dart';
  11. import 'bloc/custom_page_state.dart';
  12. import 'bloc/custom_page_event.dart';
  13. import 'bloc/custom_page_repository.dart';
  14. import 'dart:ui';
  15. ///
  16. /// 通用模块页面
  17. ///
  18. class CustomPage extends StatelessWidget {
  19. final Map<String, dynamic> data;
  20. CustomPage(this.data, {Key key}) : super(key: key);
  21. @override
  22. Widget build(BuildContext context) {
  23. // return MultiProvider(
  24. // providers: [],
  25. // child:
  26. return BlocProvider<CustomPageBloc>(
  27. create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()),
  28. child: _CommonPageContainer(),
  29. // ),
  30. );
  31. }
  32. }
  33. class _CommonPageContainer extends StatefulWidget {
  34. @override
  35. __CommonPageContainerState createState() => __CommonPageContainerState();
  36. }
  37. class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin {
  38. ScrollController _controller;
  39. RefreshController _refreshController;
  40. TabController _tabController;
  41. bool _isEnded = false;
  42. /// 回到顶点
  43. void _scrollTop() {
  44. // _controller.jumpTo(0);
  45. _controller.animateTo(0, duration: Duration(seconds: 1), curve: Curves.linear);
  46. }
  47. /// 刷新
  48. void _onRefreshEvent() async {
  49. BlocProvider.of<CustomPageBloc>(context).add(CustomPageRefreshEvent());
  50. }
  51. /// 加载更多
  52. void _onLoadEvent() async {}
  53. @override
  54. void initState() {
  55. _controller = ScrollController();
  56. _refreshController = RefreshController(initialRefresh: false);
  57. _tabController = TabController(length: 10, vsync: this);
  58. super.initState();
  59. }
  60. @override
  61. void dispose() {
  62. _controller?.dispose();
  63. _refreshController?.dispose();
  64. _tabController?.dispose();
  65. super.dispose();
  66. }
  67. @override
  68. Widget build(BuildContext context) {
  69. return MediaQuery.removePadding(
  70. context: context,
  71. child: BlocConsumer<CustomPageBloc, CustomPageState>(
  72. listener: (context, state) {},
  73. buildWhen: (prev, current) {
  74. if (current is CustomPageErrorState) {
  75. return false;
  76. }
  77. if (current is CustomPageRefreshSuccessState) {
  78. _refreshController.refreshCompleted(resetFooterState: true);
  79. return false;
  80. }
  81. if (current is CustomPageRefreshErrorState) {
  82. _refreshController.refreshFailed();
  83. return false;
  84. }
  85. return true;
  86. },
  87. builder: (context, state) {
  88. if (state is CustomPageLoadedState) {
  89. return _buildMainWidget();
  90. }
  91. if (state is CustomPageInitErrorState) {
  92. return _buildMainWidget();
  93. }
  94. return _buildSkeletonWidget();
  95. },
  96. ),
  97. );
  98. }
  99. /// 有数据
  100. Widget _buildMainWidget() {
  101. double top = MediaQueryData.fromWindow(window).padding.top;
  102. return Scaffold(
  103. backgroundColor: HexColor.fromHex('#F9F9F9'),
  104. floatingActionButton: _buildFloatWidget(),
  105. floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100),
  106. body: SmartRefresher(
  107. enablePullDown: false,
  108. enablePullUp: false,
  109. header: RefreshHeader(
  110. offsetY: top,
  111. ),
  112. controller: _refreshController,
  113. onLoading: _onLoadEvent,
  114. onRefresh: _onRefreshEvent,
  115. child: CustomScrollView(
  116. controller: _controller,
  117. slivers: [
  118. /// 标题
  119. SliverAppBar(
  120. title: Text('标题'),
  121. centerTitle: true,
  122. pinned: true,
  123. ),
  124. /// 搜索
  125. SliverPersistentHeader(
  126. delegate: CustomSliverPersistentHeaderDelegate(
  127. max: 40,
  128. min: 40,
  129. child: Container(
  130. height: double.infinity,
  131. width: double.infinity,
  132. color: Colors.yellowAccent,
  133. ),
  134. ),
  135. // pinned: true,
  136. ),
  137. /// TAB BAR
  138. SliverPersistentHeader(
  139. delegate: CustomSliverPersistentHeaderDelegate(
  140. max: 40,
  141. min: 40,
  142. child: Container(
  143. height: double.infinity,
  144. width: double.infinity,
  145. color: Colors.redAccent,
  146. child: TabBar(
  147. isScrollable: true,
  148. controller: _tabController,
  149. tabs: List.generate(10, (index) => Text('$index')),
  150. ),
  151. ),
  152. ),
  153. // pinned: true,
  154. ),
  155. /// 轮播图
  156. SliverToBoxAdapter(
  157. child: Container(
  158. height: 140,
  159. width: double.infinity,
  160. color: Colors.blueAccent,
  161. ),
  162. ),
  163. /// 多眼导航
  164. SliverToBoxAdapter(
  165. child: Container(
  166. height: 70,
  167. width: double.infinity,
  168. color: Colors.yellowAccent,
  169. ),
  170. ),
  171. /// 商品列表
  172. SliverList(
  173. delegate: SliverChildBuilderDelegate((context, index) {
  174. return Container(
  175. height: 50,
  176. width: double.infinity,
  177. color: Colors.green[(index % 9 + 1) * 100],
  178. );
  179. }, childCount: 50)),
  180. ],
  181. ),
  182. ),
  183. );
  184. }
  185. /// 悬浮按钮
  186. Widget _buildFloatWidget() {
  187. return Visibility(
  188. visible: true,
  189. child: GestureDetector(
  190. onTap: ()=> _scrollTop(),
  191. behavior: HitTestBehavior.opaque,
  192. child: Container(
  193. height: 30,
  194. width: 30,
  195. color: Colors.redAccent,
  196. ),
  197. ),
  198. );
  199. }
  200. /// 骨架图
  201. Widget _buildSkeletonWidget() {
  202. return Scaffold();
  203. }
  204. /// 空数据视图
  205. Widget _buildEmptyWidget() {
  206. return Scaffold(
  207. backgroundColor: HexColor.fromHex('#F9F9F9'),
  208. appBar: AppBar(
  209. brightness: Brightness.light,
  210. backgroundColor: Colors.white,
  211. leading: IconButton(
  212. icon: Icon(
  213. Icons.arrow_back_ios,
  214. size: 22,
  215. color: HexColor.fromHex('#333333'),
  216. ),
  217. onPressed: () => Navigator.maybePop(context),
  218. ),
  219. title: Text(
  220. '爆款',
  221. style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 15, fontWeight: FontWeight.bold),
  222. ),
  223. centerTitle: true,
  224. elevation: 0,
  225. ),
  226. body: Column(
  227. crossAxisAlignment: CrossAxisAlignment.center,
  228. mainAxisAlignment: MainAxisAlignment.center,
  229. children: <Widget>[
  230. Align(
  231. alignment: Alignment.topCenter,
  232. child: EmptyWidget(
  233. tips: '网络似乎开小差了~',
  234. ),
  235. ),
  236. GestureDetector(
  237. onTap: () => _onRefreshEvent(),
  238. behavior: HitTestBehavior.opaque,
  239. child: Container(
  240. alignment: Alignment.center,
  241. decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), border: Border.all(color: HexColor.fromHex('#999999'), width: 0.5), color: Colors.white),
  242. width: 80,
  243. height: 20,
  244. child: Text(
  245. '刷新一下',
  246. style: TextStyle(fontSize: 12, color: HexColor.fromHex('#333333'), fontWeight: FontWeight.bold),
  247. ),
  248. ),
  249. )
  250. ],
  251. ));
  252. }
  253. }
  254. class _CustomFloatingActionButtonLocation extends FloatingActionButtonLocation {
  255. FloatingActionButtonLocation location;
  256. double offsetX; // X方向的偏移量
  257. double offsetY; // Y方向的偏移量
  258. _CustomFloatingActionButtonLocation(this.location, this.offsetX, this.offsetY);
  259. @override
  260. Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {
  261. Offset offset = location.getOffset(scaffoldGeometry);
  262. return Offset(offset.dx + offsetX, offset.dy + offsetY);
  263. }
  264. }