From 03cc1f72dea72b2e1bf527add7f66fc0761e5e91 Mon Sep 17 00:00:00 2001 From: weilu Date: Wed, 31 Jul 2019 09:15:15 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E5=88=97=E8=A1=A8=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 41 ++- lib/goods/goods_edit_page.dart | 2 + lib/goods/goods_sort_dialog.dart | 2 +- lib/order/order_list.dart | 336 +++++++++++++++++++++ lib/order/order_page.dart | 489 ++++++++----------------------- 5 files changed, 484 insertions(+), 386 deletions(-) create mode 100644 lib/order/order_list.dart diff --git a/README.md b/README.md index 3d7094c5e..2b0e28a19 100755 --- a/README.md +++ b/README.md @@ -20,11 +20,14 @@ | ![](./preview/Screenshot_18.png) | ![](./preview/Screenshot_19.png) | ![](./preview/Screenshot_20.png) | ![](./preview/Screenshot_21.png) | | ![](./preview/Screenshot_22.jpg) | | | | +**觉得还可以的话,来个Star、Fork支持一波!有问题欢迎提Issue。** + ## 实现效果包括 * mvp模式 * 使用 `provider`做状态管理 -* 基于`dio`的网络请求封装(支持泛型,自动解析,基于`FlutterJsonBeanFactory`插件实现) +* 基于`dio`的网络请求封装(支持泛型,基于`FlutterJsonBeanFactory`插件实现) +* 使用`Sliver`系列组件实现复杂滚动效果 * 使用高德地图定位选择地址 * 输入框等部件的处理封装 * 自定义列表滑动效果 @@ -49,37 +52,30 @@ Android版安装包:[点击下载](https://www.pgyer.com/gYXj) iOS需要自行下载代码运行。(效果是一致的) -**注意**: - - 1. `debug`模式下会有部分卡顿现象,属于正常现象。良好的体验需要打`release` 包。 - iOS可以执行命令`flutter build ios` 以创建`release`版本。 - Android可以执行命令`flutter build apk` 以创建`release`版本。 - - 2. FlutterJsonBeanFactory插件使用可以查看[这篇文章](https://www.jianshu.com/p/e909f3f936d6) - - 3. 因为页面有点多,不清楚业务流程可能会导致部分页面无法找到。具体可以参看设计图,或者页面上随便点点。。。 - - -**觉得还可以的话,来个Star、Fork支持一波!有问题欢迎提Issue。** - ## 项目运行环境 1. Flutter version 1.7.8+hotfix.4 2. Dart version 2.4.0 +## 注意事项 -**注意**: +- `debug`模式下会有部分卡顿现象,属于正常现象。良好的体验需要打`release` 包。 + iOS可以执行命令`flutter build ios` 以创建`release`版本。 + Android可以执行命令`flutter build apk` 以创建`release`版本。 + +- FlutterJsonBeanFactory插件使用可以查看[这篇文章](https://www.jianshu.com/p/e909f3f936d6) -本人也尝试过升级过稳定版本`1.7.8+hotfix.2` 和 `1.7.8+hotfix.3`,但是因为华为小米的个别机型在删除`TextField`中的文字会导致崩溃(具体[点击查看](https://weilu.blog.csdn.net/article/details/94849020)),所以推荐采用`1.7.8+hotfix.4`。 +- 本人也尝试过升级过稳定版本`1.7.8+hotfix.2` 和 `1.7.8+hotfix.3`,但是因为华为小米的个别机型在删除`TextField`中的文字会导致崩溃(具体[点击查看](https://weilu.blog.csdn.net/article/details/94849020)),所以推荐采用`1.7.8+hotfix.4`。 -如果你的Flutter版本低于1.5.9,需要使用低版本的依赖库,请手动替换: +- 如果你的Flutter版本低于1.5.9,需要使用低版本的依赖库,请手动替换: ```dart - flustars: 0.2.5 cached_network_image: ^0.7.0 ``` + +- 因为页面有点多,不清楚业务流程可能会导致部分页面无法找到。具体可以参看设计图,或者页面上随便点点。。。 ## 使用到的三方库 @@ -118,14 +114,11 @@ iOS需要自行下载代码运行。(效果是一致的) * [ ] 项目中有使用这一套框架及组件,会同步修复及优化遇到的问题。 -## TODO - -已知问题: - - 1. ListView在没有设置分割线的情况下,个别Item之间存在大约1像素的间隔。(像素对齐问题) +## 已知问题: - 2. 输入框在不设置`obscureText`属性的情况下(false),无法弹出密码模式键盘。 +- ListView在没有设置分割线的情况下,个别Item之间存在大约1像素的间隔。([像素对齐问题](https://github.com/flutter/flutter/issues/14288)) +- 输入框在不设置`obscureText`属性的情况下(false),无法弹出密码模式键盘。(暂时使用`BlacklistingTextInputFormatter`去除可能会输入的中文) ## 心得 diff --git a/lib/goods/goods_edit_page.dart b/lib/goods/goods_edit_page.dart index 9c0e69fda..ae8d9a91f 100755 --- a/lib/goods/goods_edit_page.dart +++ b/lib/goods/goods_edit_page.dart @@ -181,6 +181,8 @@ class _GoodsEditState extends State { _showBottomSheet(){ showModalBottomSheet( context: context, + /// 使用true则高度不受16分之9的最高限制 + isScrollControlled: true, builder: (BuildContext context) { return GoodsSortDialog( onSelected: (_, name){ diff --git a/lib/goods/goods_sort_dialog.dart b/lib/goods/goods_sort_dialog.dart index b3e0e655c..41146bba6 100755 --- a/lib/goods/goods_sort_dialog.dart +++ b/lib/goods/goods_sort_dialog.dart @@ -71,7 +71,7 @@ class _GoodsSortDialogState extends State with SingleTickerProv return Material( color: Colors.white, child: Container( - height: MediaQuery.of(context).size.height * 9.0 / 16.0, + height: MediaQuery.of(context).size.height * 11.0 / 16.0, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/order/order_list.dart b/lib/order/order_list.dart new file mode 100644 index 000000000..9d5d5052b --- /dev/null +++ b/lib/order/order_list.dart @@ -0,0 +1,336 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_deer/order/order_router.dart'; +import 'package:flutter_deer/order/pay_type_dialog.dart'; +import 'package:flutter_deer/res/resources.dart'; +import 'package:flutter_deer/routers/fluro_navigator.dart'; +import 'package:flutter_deer/util/image_utils.dart'; +import 'package:flutter_deer/util/toast.dart'; +import 'package:flutter_deer/util/utils.dart'; +import 'package:flutter_deer/widgets/my_card.dart'; +import 'package:flutter_deer/widgets/state_layout.dart'; + +class OrderList extends StatefulWidget { + + const OrderList({ + Key key, + @required this.index, + @required this.tabIndex, + }): super(key: key); + + final int index; + final int tabIndex; + + @override + _OrderListState createState() => _OrderListState(); +} + +class _OrderListState extends State with AutomaticKeepAliveClientMixin{ + + var _orderLeftButtonText = ["拒单", "拒单", "订单跟踪", "订单跟踪", "订单跟踪"]; + var _orderRightButtonText = ["接单", "开始配送", "完成", "", ""]; + + /// 是否正在加载数据 + bool _isLoading = false; + int _page = 1; + final int _maxPage = 3; + StateType _stateType = StateType.loading; + int _index = 0; + ScrollController _controller = ScrollController(); + + @override + void initState() { + super.initState(); + _index = widget.index; + _onRefresh(); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return NotificationListener( + onNotification: (ScrollNotification note){ + if(note.metrics.pixels == note.metrics.maxScrollExtent){ + _loadMore(); + } + return true; + }, + child: RefreshIndicator( + onRefresh: _onRefresh, + displacement: 120.0, /// 默认40, 多添加的80为Header高度 + child: CustomScrollView( + /// 这里指定controller可以与外层NestedScrollView的滚动分离,避免一处滑动,5个Tab中的列表同步滑动。 + controller: _index != widget.tabIndex ? _controller : null, + key: PageStorageKey("$_index"), + slivers: [ + SliverOverlapInjector( + ///SliverAppBar的expandedHeight高度,避免重叠 + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + sliver: _list.isEmpty ? SliverFillRemaining(child: StateLayout(type: _stateType)) : SliverList( + delegate: SliverChildBuilderDelegate((BuildContext context, int index) { + return Container( + margin: const EdgeInsets.only(top: 8.0), + child: index < _list.length ? (index % 5 == 0 ? _buildTimeTag() : _buildOrderItem()) : _buildMoreWidget(), + ); + }, + childCount: _list.length + 1), + ), + ) + ], + ), + ), + ); + } + + List _list = []; + + Future _onRefresh() async { + await Future.delayed(Duration(seconds: 2), () { + setState(() { + _page = 1; + _list = List.generate(10, (i) => 'newItem:$i'); + }); + }); + } + + bool _hasMore(){ + return _page < _maxPage; + } + + Future _loadMore() async { + if (_isLoading) { + return; + } + if (!_hasMore()){ + return; + } + _isLoading = true; + await Future.delayed(Duration(seconds: 2), () { + setState(() { + _list.addAll(List.generate(10, (i) => 'newItem:$i')); + _page ++; + _isLoading = false; + }); + }); + } + + Widget _buildMoreWidget(){ + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Offstage(offstage: !_hasMore(), child: const CupertinoActivityIndicator()), + Offstage(offstage: !_hasMore(), child: Gaps.hGap5), + Text(!_hasMore() ? '没有了呦~' : '正在加载中...', style: TextStyle(color: const Color(0x8A000000))), + ], + ), + ); + } + + Widget _buildOrderItem(){ + return MyCard( + child: Container( + padding: const EdgeInsets.all(16.0), + child: InkWell( + onTap: (){ + NavigatorUtils.push(context, OrderRouter.orderInfoPage); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + "15000000000(郭李)", + style: TextStyles.textDark14, + ), + ), + Text( + "货到付款", + style: TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_red + ), + ), + ], + ), + Gaps.vGap8, + Text( + "西安市雁塔区 鱼化寨街道唐兴路唐兴数码3楼318", + style: TextStyles.textNormal12, + ), + Gaps.vGap8, + Gaps.line, + Gaps.vGap8, + RichText( + text: TextSpan( + children: [ + TextSpan(text: '清凉一度抽纸', style: TextStyles.textDark12), + TextSpan(text: ' x1', style: TextStyles.textGray12), + ], + ) + ), + Gaps.vGap8, + RichText( + text: TextSpan( + children: [ + TextSpan(text: '清凉一度抽纸', style: TextStyles.textDark12), + TextSpan(text: ' x2', style: TextStyles.textGray12), + ], + ) + ), + Gaps.vGap12, + Row( + children: [ + Expanded( + child: RichText( + text: TextSpan( + children: [ + TextSpan(text: '¥20.00', style: TextStyles.textDark12), + TextSpan(text: ' 共3件商品', style: TextStyles.textGray10), + ], + ) + ), + ), + Text( + "2018.02.05 10:00", + style: TextStyles.textDark12, + ), + ], + ), + Gaps.vGap8, + Gaps.line, + Gaps.vGap8, + Theme( // 修改button默认的最小宽度与padding + data: Theme.of(context).copyWith( + buttonTheme: ButtonThemeData( + padding: const EdgeInsets.symmetric(horizontal: 14.0), + minWidth: 64.0, + height: 30.0, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, // 距顶部距离为0 + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4.0), + ) + ), + textTheme: TextTheme( + button: TextStyle( + fontSize: Dimens.font_sp14, + ) + ), + ), + child: Row( + children: [ + FlatButton( + color: Colours.bg_gray, + child: Text("联系客户"), + onPressed: (){ + _showCallPhoneDialog("15000000000"); + }, + ), + Expanded( + child: Gaps.empty, + ), + FlatButton( + color: Colours.bg_gray, + child: Text(_orderLeftButtonText[_index]), + onPressed: (){ + if (_index >= 2){ + NavigatorUtils.push(context, OrderRouter.orderTrackPage); + } + }, + ), + Offstage( + offstage: _orderRightButtonText[_index].length == 0, + child: Gaps.hGap10, + ), + Offstage( + offstage: _orderRightButtonText[_index].length == 0, + child: FlatButton( + color: Colours.app_main, + textColor: Colors.white, + onPressed: (){ + if (_index == 2){ + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return PayTypeDialog( + onPressed: (index, type){ + Toast.show("收款类型:$type"); + }, + ); + }); + } + }, + child: Text(_orderRightButtonText[_index]), + ), + ), + ], + ), + ) + ], + ), + ), + ), + ); + } + + void _showCallPhoneDialog(String phone){ + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: Text('提示'), + content: Text('是否拨打:$phone ?'), + actions: [ + FlatButton( + onPressed: () => NavigatorUtils.goBack(context), + child: Text('取消'), + ), + FlatButton( + onPressed: (){ + Utils.launchTelURL(phone); + NavigatorUtils.goBack(context); + }, + textColor: Colours.text_red, + child: Text('拨打'), + ), + ], + ); + }); + } + + Widget _buildTimeTag(){ + return MyCard( + child: Container( + height: 34.0, + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + loadAssetImage("order/icon_calendar", width: 14.0, height: 14.0), + Gaps.hGap10, + Text( + "2019年2月5日", + style: TextStyles.textDark14, + ), + Expanded(child: Container()), + Text( + "4单", + style: TextStyles.textDark14, + ) + ], + ), + )); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/order/order_page.dart b/lib/order/order_page.dart index 275bade40..31c1cea63 100755 --- a/lib/order/order_page.dart +++ b/lib/order/order_page.dart @@ -2,99 +2,100 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_deer/order/order_list.dart'; import 'package:flutter_deer/res/resources.dart'; import 'package:flutter_deer/routers/fluro_navigator.dart'; import 'package:flutter_deer/util/image_utils.dart'; -import 'package:flutter_deer/util/toast.dart'; import 'package:flutter_deer/util/utils.dart'; import 'package:flutter_deer/widgets/my_card.dart'; import 'package:flutter_deer/widgets/my_flexible_space_bar.dart'; -import 'package:flutter_deer/widgets/state_layout.dart'; import 'order_router.dart'; -import 'pay_type_dialog.dart'; class Order extends StatefulWidget { @override _OrderState createState() => _OrderState(); } -class _OrderState extends State with AutomaticKeepAliveClientMixin{ +class _OrderState extends State with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin{ @override bool get wantKeepAlive => true; + TabController _tabController; int _index = 0; - var _orderLeftButtonText = ["拒单", "拒单", "订单跟踪", "订单跟踪", "订单跟踪"]; - var _orderRightButtonText = ["接单", "开始配送", "完成", "", ""]; - - /// 是否正在加载数据 - bool _isLoading = false; - int _page = 1; - final int _maxPage = 3; - StateType _stateType = StateType.loading; @override void initState() { super.initState(); - _onRefresh(); + _tabController = TabController(vsync: this, length: 5); } - + + @override + void dispose() { + _tabController?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { super.build(context); return Scaffold( - body: NotificationListener( - onNotification: (ScrollNotification note){ - if(note.metrics.pixels == note.metrics.maxScrollExtent){ - _loadMore(); - } - return true; + body: NestedScrollView( + physics: ClampingScrollPhysics(), + headerSliverBuilder: (context, innerBoxIsScrolled) { + return _sliverBuilder(context); }, - /// 问题参看:https://github.com/flutter/flutter/issues/34727 - /// 原生方案中,暂时可以采取的最好方案了 - child: RefreshIndicator( - onRefresh: _onRefresh, - child: CustomScrollView( - physics: ClampingScrollPhysics(), - slivers: _sliverBuilder(), - ), + body: PageView.builder( + itemCount: 5, + onPageChanged: (index) { + if (_isPageCanChanged) { + _onPageChange(index); + } + }, + controller: _pageController, + itemBuilder: (_, index) { + return OrderList(index: index, tabIndex: _index); + }, ), ), ); } - - List _sliverBuilder() { + + List _sliverBuilder(BuildContext context) { return [ - SliverAppBar( - leading: Container(), - actions: [ - IconButton( - onPressed: (){ - NavigatorUtils.push(context, OrderRouter.orderSearchPage); - }, - icon: loadAssetImage("order/icon_search", - width: 22.0, - height: 22.0, + SliverOverlapAbsorber( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + child: SliverAppBar( + leading: Container(), + actions: [ + IconButton( + onPressed: (){ + NavigatorUtils.push(context, OrderRouter.orderSearchPage); + }, + icon: loadAssetImage("order/icon_search", + width: 22.0, + height: 22.0, + ), + ) + ], + backgroundColor: Colors.transparent, + elevation: 0.0, + centerTitle: true, + expandedHeight: 100.0, + floating: false, // 不随着滑动隐藏标题 + pinned: true, // 固定在顶部 + flexibleSpace: MyFlexibleSpaceBar( + background: loadAssetImage("order/order_bg", + width: double.infinity, + height: 113.0, + fit: BoxFit.fill, ), - ) - ], - backgroundColor: Colors.transparent, - elevation: 0.0, - centerTitle: true, - expandedHeight: 100.0, - floating: false, // 不随着滑动隐藏标题 - pinned: true, // 固定在顶部 - flexibleSpace: MyFlexibleSpaceBar( - background: loadAssetImage("order/order_bg", - width: double.infinity, - height: 113.0, - fit: BoxFit.fill, + centerTitle: true, + titlePadding: const EdgeInsetsDirectional.only(start: 16.0, bottom: 14.0), + collapseMode: CollapseMode.pin, + title: Text('订单'), ), - centerTitle: true, - titlePadding: const EdgeInsetsDirectional.only(start: 16.0, bottom: 14.0), - collapseMode: CollapseMode.pin, - title: Text('订单'), ), ), SliverPersistentHeader( @@ -103,335 +104,101 @@ class _OrderState extends State with AutomaticKeepAliveClientMixin DecoratedBox( decoration: BoxDecoration( image: DecorationImage( - image: AssetImage(Utils.getImgPath("order/order_bg1")), - fit: BoxFit.fill + image: AssetImage(Utils.getImgPath("order/order_bg1")), + fit: BoxFit.fill ) ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - children: [ - MyCard( - child: Container( - height: 80.0, - padding: const EdgeInsets.only(top: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildTabView(0, "order/xdd_s", "order/xdd_n", '新订单'), - _buildTabView(1, "order/dps_s", "order/dps_n", '待配送'), - _buildTabView(2, "order/dwc_s", "order/dwc_n", '待完成'), - _buildTabView(3, "order/ywc_s", "order/ywc_n", '已完成'), - _buildTabView(4, "order/yqx_s", "order/yqx_n", '已取消'), - ], - ), - ), + child: MyCard( + child: Container( + height: 80.0, + padding: const EdgeInsets.only(top: 8.0), + child: TabBar( + labelPadding: const EdgeInsets.symmetric(horizontal: 0), + controller: _tabController, + labelColor: Colours.text_dark, + unselectedLabelColor: Colours.text_dark, + labelStyle: TextStyles.textBoldDark14, + unselectedLabelStyle: TextStyles.textDark14, + indicatorColor: Colors.transparent, + tabs: [ + _buildTabView(0, "order/xdd_s", "order/xdd_n", '新订单'), + _buildTabView(1, "order/dps_s", "order/dps_n", '待配送'), + _buildTabView(2, "order/dwc_s", "order/dwc_n", '待完成'), + _buildTabView(3, "order/ywc_s", "order/ywc_n", '已完成'), + _buildTabView(4, "order/yqx_s", "order/yqx_n", '已取消'), + ], + onTap: (index){ + if (!mounted){ + return; + } + _pageController.jumpToPage(index); + _index = index; + setState(() { + + }); + }, ), - ], + ), ), ), ) - , 80.0 - ), - ), - SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - sliver: _list.isEmpty ? SliverFillRemaining(child: StateLayout(type: _stateType)) : SliverList( - delegate: SliverChildBuilderDelegate((BuildContext context, int index) { - return Container( - margin: const EdgeInsets.only(top: 8.0), - child: index < _list.length ? (index % 5 == 0 ? _buildTimeTag() : _buildOrderItem()) : _buildMoreWidget(), - ); - }, - childCount: _list.length + 1), + , 80.0 ), ), + ]; } - List _list = []; - - Future _onRefresh() async { - await Future.delayed(Duration(seconds: 2), () { - setState(() { - _page = 1; - _list = List.generate(10, (i) => 'newItem:$i'); - }); - }); - } - - bool _hasMore(){ - return _page < _maxPage; - } + var _isPageCanChanged = true; + PageController _pageController = PageController(initialPage: 0); + _onPageChange(int index, {PageController p, TabController t}) async { - Future _loadMore() async { - if (_isLoading) { - return; + if (p != null) {//判断是哪一个切换 + _isPageCanChanged = false; + await _pageController.animateToPage(index, duration: Duration(milliseconds: 300), curve: Curves.ease);//等待pageview切换完毕,再释放pageivew监听 + _isPageCanChanged = true; + } else { + _tabController.animateTo(index);//切换Tabbar } - if (!_hasMore()){ - return; - } - _isLoading = true; - await Future.delayed(Duration(seconds: 2), () { - setState(() { - _list.addAll(List.generate(10, (i) => 'newItem:$i')); - _page ++; - _isLoading = false; - }); + _index = index; + setState(() { + }); } - - Widget _buildMoreWidget(){ - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Offstage(offstage: !_hasMore(), child: const CupertinoActivityIndicator()), - Offstage(offstage: !_hasMore(), child: Gaps.hGap5), - Text(!_hasMore() ? '没有了呦~' : '正在加载中...', style: TextStyle(color: const Color(0x8A000000))), - ], - ), - ); - } - - Widget _buildOrderItem(){ - return MyCard( - child: Container( - padding: const EdgeInsets.all(16.0), - child: InkWell( - onTap: (){ - NavigatorUtils.push(context, OrderRouter.orderInfoPage); - }, + + Widget _buildTabView(int index, String selImg, String unImg, String text){ + return Stack( + children: [ + Container( + width: 46.0, + padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Row( - children: [ - Expanded( - child: Text( - "15000000000(郭李)", - style: TextStyles.textDark14, - ), - ), - Text( - "货到付款", - style: TextStyle( - fontSize: Dimens.font_sp12, - color: Colours.text_red - ), - ), - ], - ), - Gaps.vGap8, - Text( - "西安市雁塔区 鱼化寨街道唐兴路唐兴数码3楼318", - style: TextStyles.textNormal12, - ), - Gaps.vGap8, - Gaps.line, - Gaps.vGap8, - RichText( - text: TextSpan( - children: [ - TextSpan(text: '清凉一度抽纸', style: TextStyles.textDark12), - TextSpan(text: ' x1', style: TextStyles.textGray12), - ], - ) - ), - Gaps.vGap8, - RichText( - text: TextSpan( - children: [ - TextSpan(text: '清凉一度抽纸', style: TextStyles.textDark12), - TextSpan(text: ' x2', style: TextStyles.textGray12), - ], - ) - ), - Gaps.vGap12, - Row( - children: [ - Expanded( - child: RichText( - text: TextSpan( - children: [ - TextSpan(text: '¥20.00', style: TextStyles.textDark12), - TextSpan(text: ' 共3件商品', style: TextStyles.textGray10), - ], - ) - ), - ), - Text( - "2018.02.05 10:00", - style: TextStyles.textDark12, - ), - ], - ), - Gaps.vGap8, - Gaps.line, - Gaps.vGap8, - Theme( // 修改button默认的最小宽度与padding - data: Theme.of(context).copyWith( - buttonTheme: ButtonThemeData( - padding: const EdgeInsets.symmetric(horizontal: 14.0), - minWidth: 64.0, - height: 30.0, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, // 距顶部距离为0 - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4.0), - ) - ), - textTheme: TextTheme( - button: TextStyle( - fontSize: Dimens.font_sp14, - ) - ), - ), - child: Row( - children: [ - FlatButton( - color: Colours.bg_gray, - child: Text("联系客户"), - onPressed: (){ - _showCallPhoneDialog("15000000000"); - }, - ), - Expanded( - child: Gaps.empty, - ), - FlatButton( - color: Colours.bg_gray, - child: Text(_orderLeftButtonText[_index]), - onPressed: (){ - if (_index >= 2){ - NavigatorUtils.push(context, OrderRouter.orderTrackPage); - } - }, - ), - Offstage( - offstage: _orderRightButtonText[_index].length == 0, - child: Gaps.hGap10, - ), - Offstage( - offstage: _orderRightButtonText[_index].length == 0, - child: FlatButton( - color: Colours.app_main, - textColor: Colors.white, - onPressed: (){ - if (_index == 2){ - showElasticDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return PayTypeDialog( - onPressed: (index, type){ - Toast.show("收款类型:$type"); - }, - ); - }); - } - }, - child: Text(_orderRightButtonText[_index]), - ), - ), - ], - ), - ) + loadAssetImage(_index == index ? selImg : unImg, width: 24.0, height: 24.0,), + Gaps.vGap4, + Text(text) ], ), ), - ), - ); - } - - void _showCallPhoneDialog(String phone){ - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return AlertDialog( - title: Text('提示'), - content: Text('是否拨打:$phone ?'), - actions: [ - FlatButton( - onPressed: () => NavigatorUtils.goBack(context), - child: Text('取消'), - ), - FlatButton( - onPressed: (){ - Utils.launchTelURL(phone); - NavigatorUtils.goBack(context); - }, - textColor: Colours.text_red, - child: Text('拨打'), - ), - ], - ); - }); - } - - Widget _buildTimeTag(){ - return MyCard( - child: Container( - height: 34.0, - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Row( - children: [ - loadAssetImage("order/icon_calendar", width: 14.0, height: 14.0), - Gaps.hGap10, - Text( - "2019年2月5日", - style: TextStyles.textDark14, - ), - Expanded(child: Container()), - Text( - "4单", - style: TextStyles.textDark14, - ) - ], - ), - )); - } - - Widget _buildTabView(int index, String selImg, String unImg, String text){ - return InkWell( - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - loadAssetImage(_index == index ? selImg : unImg, width: 24.0, height: 24.0,), - Gaps.vGap4, - Text(text, style: TextStyle(fontWeight: _index == index ? FontWeight.bold : FontWeight.normal)) - ], + Positioned( + right: 0.0, + child: index < 3 ? DecoratedBox( + decoration: BoxDecoration( + color: Colours.text_red, + borderRadius: BorderRadius.circular(11.0), ), - ), - Positioned( - right: 0.0, - child: index < 3 ? DecoratedBox( - decoration: BoxDecoration( - color: Colours.text_red, - borderRadius: BorderRadius.circular(11.0), - ), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 2.0), - child: Text("10", style: TextStyle(color: Colors.white, fontSize: Dimens.font_sp12),), - ), - ) : Gaps.empty, - ) - ], - ), - onTap: (){ - setState(() { - _index = index; - }); - }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 2.0), + child: Text("10", style: TextStyle(color: Colors.white, fontSize: Dimens.font_sp12),), + ), + ) : Gaps.empty, + ) + ], ); } - } class SliverAppBarDelegate extends SliverPersistentHeaderDelegate {