|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- import 'dart:convert';
-
- import 'package:flutter/cupertino.dart';
- import 'package:pull_to_refresh/pull_to_refresh.dart';
- import 'package:tab_indicator_styler/tab_indicator_styler.dart';
- import 'package:zhiying_base_widget/pages/custom_page/custom_item_page.dart';
- import 'package:zhiying_base_widget/pages/main_page/model/background_model.dart';
- import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart';
- import 'package:zhiying_base_widget/widgets/custom/search/custom_search_widget.dart';
- import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart';
- import 'package:zhiying_base_widget/widgets/others/mine_header_bg_widget.dart';
- import 'package:zhiying_comm/zhiying_comm.dart';
- import 'package:flutter/material.dart';
- import 'package:provider/provider.dart';
- import 'package:flutter_bloc/flutter_bloc.dart';
- import 'bloc/background_bloc.dart';
- import 'bloc/custom_page_bloc.dart';
- import 'bloc/custom_page_state.dart';
- import 'bloc/custom_page_event.dart';
- import 'bloc/custom_page_repository.dart';
- import 'dart:ui';
- import 'package:fluttertoast/fluttertoast.dart';
-
- ///
- /// 通用模块页面
- ///
- class CustomPage extends StatefulWidget {
- final Map<String, dynamic> data;
-
- CustomPage(this.data, {Key key}) : super(key: key);
-
- @override
- _CustomPageState createState() => _CustomPageState();
- }
-
- class _CustomPageState extends State<CustomPage> {
- @override
- Widget build(BuildContext context) {
- Logger.log("数据: " + widget?.data.toString());
- return MultiProvider(
- providers: [
- ChangeNotifierProvider.value(value: MainPageBgNotifier()),
- ],
- child: BlocProvider<CustomPageBloc>(
- create: (_) => CustomPageBloc(CustomPageRepository(data: widget?.data))..add(CustomPageInitEvent()),
- child: _CommonPageContainer(widget?.data),
- // ),
- ),
- );
- }
- }
-
- class _CommonPageContainer extends StatefulWidget {
- final Map<String, dynamic> data;
-
- _CommonPageContainer(this.data);
-
- @override
- __CommonPageContainerState createState() => __CommonPageContainerState();
- }
-
- class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin ,AutomaticKeepAliveClientMixin{
- TabController _tabController;
-
- // 是否有AppBar
- bool _isHasAppbar = false;
-
- // 是否有TabBar
- bool _isHasTabBar = false;
-
- double backgroundTopMargin = 0;
-
- BackgroundBloc backgroundBloc;
-
- /// 刷新
- void _onRefreshEvent() async {
- BlocProvider.of<CustomPageBloc>(context).add(CustomPageRefreshEvent());
- }
-
- @override
- void initState() {
- backgroundBloc=BackgroundBloc();
- super.initState();
- }
-
- @override
- void dispose() {
- _tabController?.dispose();
- backgroundBloc.streamController.close();
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- return MediaQuery.removePadding(
- context: context,
- child: BlocConsumer<CustomPageBloc, CustomPageState>(
- listener: (context, state) {},
- buildWhen: (prev, current) {
- if (current is CustomPageErrorState) {
- return false;
- }
- if (current is CustomPageRefreshSuccessState) {
- // _refreshController.refreshCompleted(resetFooterState: true);
- return false;
- }
- if (current is CustomPageRefreshErrorState) {
- // _refreshController.refreshFailed();
- return false;
- }
- return true;
- },
- builder: (context, state) {
- /// 有数据
- if (state is CustomPageLoadedState) {
- if (EmptyUtil.isEmpty(state.model)) return _buildEmptyWidget();
- return _buildMainWidget(state.model, state.backgroundModel);
- }
-
- /// 初始化失败
- if (state is CustomPageInitErrorState) {
- return _buildEmptyWidget();
- }
-
- /// 骨架图
- return _buildSkeletonWidget();
- },
- ),
- );
- }
-
- /// 有数据
- Widget _buildMainWidget(List<Map<String, dynamic>> model, BackgroundModel backgroundModel) {
- return Scaffold(
- appBar: _buildAppbar(model?.first),
- backgroundColor: HexColor.fromHex(backgroundModel?.bgColor == null || backgroundModel?.bgColor == '' ? "#FFF9F9F9" : backgroundModel?.bgColor ?? "#FFF9F9F9"),
- // floatingActionButton: _buildFloatWidget(),
- floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100),
- body: Stack(
- children: <Widget>[
- _buildBackground(backgroundModel),
- Column(children: _buildFirstWidget(model, backgroundModel)),
- ],
- ),
- );
- }
-
- /// 骨架图
- Widget _buildSkeletonWidget() {
- return Scaffold();
- }
-
- /// 空数据视图
- Widget _buildEmptyWidget() {
- return Scaffold(
- backgroundColor: HexColor.fromHex('#F9F9F9'),
- appBar: AppBar(
- brightness: Brightness.light,
- backgroundColor: Colors.white,
- leading: IconButton(
- icon: Icon(
- Icons.arrow_back_ios,
- size: 22,
- color: HexColor.fromHex('#333333'),
- ),
- onPressed: () => Navigator.maybePop(context),
- ),
- title: Text(
- '',
- style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 18, fontWeight: FontWeight.bold),
- ),
- centerTitle: true,
- elevation: 0,
- ),
- body: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisAlignment: MainAxisAlignment.center,
- children: <Widget>[
- Align(
- alignment: Alignment.topCenter,
- child: EmptyWidget(
- tips: '网络似乎开小差了~',
- ),
- ),
- GestureDetector(
- onTap: () => _onRefreshEvent(),
- behavior: HitTestBehavior.opaque,
- child: Container(
- alignment: Alignment.center,
- decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), border: Border.all(color: HexColor.fromHex('#999999'), width: 0.5), color: Colors.white),
- width: 80,
- height: 20,
- child: Text(
- '刷新一下',
- style: TextStyle(fontSize: 12, color: HexColor.fromHex('#333333'), fontWeight: FontWeight.bold),
- ),
- ),
- )
- ],
- ));
- }
-
- /// 数据,生成第一层widget
- List<Widget> _buildFirstWidget(List<Map<String, dynamic>> model, BackgroundModel backgroundModel) {
- List<Widget> result = [];
-
- // 分类导航的key ⚠️ 这里先写成Test 后续要改
- const String CATEGORY_KEY = 'category';
- // 判断是否有分类导航
- // 判断最后一个是否属于分类导航,如果属于,则有分类导航,如果不是,则无分类导航
- bool haveCategory = !EmptyUtil.isEmpty(model?.last) && model.last.containsKey('mod_name') && model.last['mod_name'] == CATEGORY_KEY;
- int endIndexLength = model.length;
- // 如果没有分类导航,则取分类导航之上的所有mod
- if (!haveCategory) {
- for (int i = 0; i < model.length; i++) {
- Map<String, dynamic> item = model[i];
- if (item['mod_name'] == CATEGORY_KEY) {
- endIndexLength = (i + 1);
- break;
- }
- }
- }
-
- for (int i = 0; i < endIndexLength; i++) {
- WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(model[i]));
- // last model
- if (i == endIndexLength - 1) {
- result.addAll(_buildTabBar(model[i], i));
- break;
- }
-
- // appBar 无需在这里添加
- if (item.modName.contains('appbar')) {
- continue;
- }
- result.addAll(WidgetFactory.create(item.modName, isSliver: false, model: model[i]));
- }
-
- // 没有appbar并且没有tabbar,则给第一个元素加边距
- if (!_isHasAppbar) {
- result.insert(0, SizedBox(height: MediaQueryData.fromWindow(window).padding.top, child: Container(color: HexColor.fromHex(backgroundModel?.headerBg?.mainColor))));
- }
-
- return result;
- }
-
- /// appbar
- Widget _buildAppbar(final Map<String, dynamic> model) {
- if (EmptyUtil.isEmpty(model)) return null;
- String mobName = model['mod_name'];
- if (!mobName.contains('_appbar')) return null;
- Map<String, dynamic> data = Map<String, dynamic>();
- try {
- data = jsonDecode(model['data']);
- } catch (e, s) {
- Logger.warn(e, s);
- }
- String parentTitle = !EmptyUtil.isEmpty(widget?.data) ? widget?.data['title'] ?? '' : '';
- _isHasAppbar = true;
- return AppBar(
- backgroundColor: HexColor.fromHex(null != data ? data['app_bar_bg_color'] ?? '#FFFFFF' : '#FFFFFF'),
- brightness: Brightness.light,
- leading: IconButton(
- icon: Icon(
- Icons.arrow_back_ios,
- size: 22,
- color: HexColor.fromHex('#333333'),
- ),
- onPressed: () => Navigator.maybePop(context),
- ),
- title: Text(
- null != data && data.containsKey('app_bar_name') ? data['app_bar_name'] != '自定义页面' ? data['app_bar_name'] : parentTitle : parentTitle,
- style: TextStyle(
- color: HexColor.fromHex(null != data ? data['app_bar_name_color'] ?? '#333333' : '#333333'),
- fontSize: 16,
- fontWeight: FontWeight.bold,
- ),
- ),
- centerTitle: true,
- elevation: 0,
- );
- }
-
- /// tabBar
- List<Widget> _buildTabBar(final Map<String, dynamic> model, final int index) {
- Map<String, dynamic> data = Map<String, dynamic>();
- List<Map<String, dynamic>> listStyle = [];
- List<Widget> result = [];
- try {
- data = jsonDecode(model['data']);
- listStyle = List.from(data['list_style']);
- } catch (e, s) {
- Logger.warn(e, s);
- }
-
- // 1、导航栏没开启的情况 传null进去进行获取没开启导航栏的widget集合
- if (EmptyUtil.isEmpty(listStyle)) {
- result.add(Expanded(
- child: CustomItemPage(
- null,
- 0,
- model['mod_id']?.toString() ?? null,
- model['mod_pid']?.toString() ?? null,
- (!_isHasAppbar && index == 0),
- scroller: _listenScroller,
- ),
- ));
- return result;
- }
-
- // 2、导航栏开启的情况
- if (listStyle.length > 0) {
- // tabContorller 初始化
- if (null == _tabController || _tabController.length != listStyle.length) {
- _tabController = new TabController(length: listStyle.length, vsync: this);
- }
-
- result.add(Container(
- height: 40,
- width: double.infinity,
- color: HexColor.fromHex(data['bg_color']),
- child: TabBar(
- controller: _tabController,
- isScrollable: /*listStyle.length <= 5 ? false : */ true,
- labelColor: HexColor.fromHex(data['choose_text_color'] ?? '#FF4242'),
- labelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
- unselectedLabelColor: HexColor.fromHex(data['text_color'] ?? '#999999'),
- unselectedLabelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
- indicatorSize: TabBarIndicatorSize.label,
- indicator: MaterialIndicator(
- color: HexColor.fromHex(data['choose_color'] ?? '#FF4242'),
- bottomLeftRadius: 1.25,
- topLeftRadius: 1.25,
- topRightRadius: 1.25,
- bottomRightRadius: 1.25,
- height: 2.5,
- horizontalPadding: 5,
- ),
- tabs: listStyle.map((e) => Text(e['name'])).toList(),
- ),
- ));
-
- _isHasTabBar = true;
- // 最后添加TabBarView
- result.add(Expanded(
- child: TabBarView(
- controller: _tabController,
- children: _buildTabBarViewChildren(listStyle, model['mod_id']?.toString(), model['mod_pid']?.toString(), index),
- ),
- ));
- }
- return result;
- }
-
- /// 返回TabBarView的视图
- List<Widget> _buildTabBarViewChildren(final List<Map<String, dynamic>> listStyle, final String modId, final String modPid, final int index) {
- List<Widget> result = [];
- for (int i = 0; i < listStyle.length; i++) {
- result.add(CustomItemPage(
- listStyle[i],
- i,
- modId,
- modPid,
- (!_isHasAppbar && !_isHasTabBar && index == 0),
- scroller: _listenScroller,
- ));
- }
- return result;
- }
-
-
- _buildBackground(BackgroundModel backgroundModel) {
- if (backgroundModel != null) {
- var headerBg = backgroundModel.headerBg;
- return StreamBuilder(
- stream: backgroundBloc.outData,
- builder: (context,asncy){
- return Container(
- constraints: BoxConstraints(minHeight: 0),
- height: (double.tryParse(headerBg?.height)??0)+backgroundTopMargin ?? 0,
- width: double.infinity,
- decoration: BoxDecoration(
- gradient: LinearGradient(
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- colors: [HexColor.fromHex(headerBg?.mainColor ?? ""), HexColor.fromHex(headerBg?.assistColor ?? ""), HexColor.fromHex(headerBg?.minorColor ?? "")])),
- );
- },
- );
-
- } else {
- return Container();
- }
- }
-
- // /// 悬浮按钮
- // Widget _buildFloatWidget() {
- // return Visibility(
- // visible: true,
- // child: GestureDetector(
- // onTap: () => _scrollTop(),
- // behavior: HitTestBehavior.opaque,
- // child: Container(
- // height: 30,
- // width: 30,
- // child: Icon(Icons.arrow_upward),
- // ),
- // ),
- // );
- // }
-
- ///监听页面滚动
- _listenScroller(double offset) {
- if (offset >= 0) {
- backgroundTopMargin = -offset;
- if (backgroundTopMargin > -500) {
- backgroundBloc.streamController.add("");
- }
- }
- }
-
- @override
- // TODO: implement wantKeepAlive
- bool get wantKeepAlive =>true;
- }
-
- /// 回到顶部的icon
- class _CustomFloatingActionButtonLocation extends FloatingActionButtonLocation {
- FloatingActionButtonLocation location;
- double offsetX; // X方向的偏移量
- double offsetY; // Y方向的偏移量
- _CustomFloatingActionButtonLocation(this.location, this.offsetX, this.offsetY);
-
- @override
- Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {
- Offset offset = location.getOffset(scaffoldGeometry);
- return Offset(offset.dx + offsetX, offset.dy + offsetY);
- }
- }
|