Flutter之商城实战(上)
一、fluro路由搭建
initialRoute:是项目的根路由,初始化的时候最先展示的页面 onGenerateRoute(RouteFactory类型函数):路由钩子,可以对某些指定的路由进行拦截,有时候不想改变页面结构,但是又想要求跳转到这个页面的时候可以用到,比如,页面设定了传参你进行跳转的候。 onUnknownRoute(RouteFactory类型函数):在路由匹配不到的时候用到,一般都返回一个统一的错误页面或404页面
配置yaml文件
#路由导航
fluro: 1.7.8
第一步:
在lib文件下新建一个文件夹Router,下面创建一个文件application.dart application.dart
import 'package:fluro/fluro.dart';
class Application {
static FluroRouter router;
}
Fluro源文件实例化 第二步: Router,下面创建一个文件routers.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart' hide Router;
import 'package:myshop_flutter/router/router_handlers.dart';
class Routers {
static String root = "/";
static String home = "/home";
static String categoryGoodsList = "/categoryGoodsList";
static String goodsDetail = "/goodsDetail";
static String login = "/login";
static String register = "/register";
static String fillInOrder = "/fillInOrder";
static String address = "/myAddress";
static String addressEdit = "/addressEdit";
static String mineCollect = "/mineCollect";
static String aboutUs = "/aboutUs";
static String mineOrder = "/mineOrder";
static String mineOrderDetail = "/mineOrderDetail";
static String webView = "/webView";
static String brandDetail = "/brandDetail";
static void configureRoutes(FluroRouter router) {
router.notFoundHandler = Handler(handlerFunc:
(BuildContext context, Map<String, List<String>> parameters) {
print("handler not find");
});
router.define(root, handler: loadingHandler);
router.define(home, handler: homeHandler);
router.define(categoryGoodsList, handler: categoryGoodsListHandler);
router.define(login, handler: loginHandler);
router.define(register, handler: registerHandler);
router.define(goodsDetail, handler: goodsDetailsHandler);
router.define(fillInOrder, handler: fillInOrderHandler);
router.define(address, handler: addressHandler);
router.define(addressEdit, handler: addressEditHandler);
router.define(aboutUs, handler: aboutHandler);
router.define(mineOrder, handler: orderHandler);
}
}
创建router_handlers.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:myshop_flutter/page/CategoryPage/GoodCategory/goods_category_page.dart';
import 'package:myshop_flutter/page/CategoryPage/GoodCategory/goods_detail_page.dart';
import 'package:myshop_flutter/page/Mine/AddressEditPage.dart';
import 'package:myshop_flutter/page/Mine/AddressPage.dart';
import 'package:myshop_flutter/page/Mine/about_us_page.dart';
import 'package:myshop_flutter/page/home/index_page.dart';
import 'package:myshop_flutter/page/loading/loading_page.dart';
import 'package:myshop_flutter/page/order/FillInOrderPage.dart';
import 'package:myshop_flutter/page/order/OrderPage.dart';
import 'package:myshop_flutter/page/user/LoginPage.dart';
import 'package:myshop_flutter/page/user/RegisterPage.dart';
import 'package:myshop_flutter/utils/string_util.dart';
var homeHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
return const HomeIndexPage();});
var loginHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
return const LoginPage();
});
var loadingHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
return LoadingPage();
});
var registerHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
return RegisterPage();
});
var categoryGoodsListHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<Object>> parameters) {
var cateforyName = StringUtil.decode(parameters["categoryName"].first).toString();
print("cateforyName" + cateforyName);
print("categoryId" + parameters["categoryId"].first);
var categoryId = int.parse(parameters["categoryId"].first);
return GoodsCategoryPage(categoryName: cateforyName, categoryId: categoryId);
});
var goodsDetailsHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<Object>> parameters) {
var goodsId = int.parse(parameters["goodsId"].first);
return GoodsDetailPage(goodsId: goodsId);
});
var orderHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
return OrderPage();
});
var fillInOrderHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
var cartId = int.parse(parameters["cartId"].first);
return FillInOrderPage(cartId);
});
var aboutHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
return AboutUsPage();
});
var addressHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
return AddressPage();
});
var addressEditHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters) {
var addressId = int.parse(parameters["addressId"].first);
return AddressEditPage(addressId);
});
main.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:myshop_flutter/router/application.dart';
import 'package:myshop_flutter/router/routers.dart';
void main() {
final router = FluroRouter();
Routers.configureRoutes(router);
Application.router = router;
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
onGenerateRoute: Application.router.generator,
theme: ThemeData(
textTheme: TextTheme(
bodyText1: TextStyle(color: Colors.red,fontSize: 24)
)
),
);
}
}
配置根路由
二、配置需要的颜色、样式、图标、标题、api
新建config文件
color.dart
import 'dart:ui';
import 'package:flutter/material.dart';
class KColor{
static const Color primaryColor = Colors.red;
static const Color defaultTextColor = Colors.redAccent;
static const Color defaultButtonColor = Colors.redAccent;
static const Color defaultSwitchColor = Colors.redAccent;
static const Color defaultCheckBoxColor = Colors.redAccent;
static const Color toastBgColor = Colors.redAccent;
static const Color watingColor = Colors.redAccent;
static const Color toastTextColor = Colors.white;
static const Color priceColor = Colors.redAccent;
static const Color indexTabSelectedColor = Colors.red;
static const Color indexTabUnSelectedColor = Colors.grey;
static const Color bannerDefaultColor = Colors.white;
static const Color bannerActiveColor = Colors.red;
static const Color categorySelectedColor = Colors.redAccent;
static const Color categoryDefaultColor = Colors.black54;
static const Color noDataTextColor = Colors.redAccent;
static const Color loginButtonColor = Colors.redAccent;
static const Color loginIconColor = Colors.redAccent;
static const Color registerTextColor = Colors.redAccent;
static const Color registerButtonColor = Colors.redAccent;
static const Color registerIconColor = Colors.redAccent;
static const Color collectionButtonColor = Colors.redAccent;
static const Color unCollectionButtonColor = Colors.grey;
static const Color addCartIconColor = Colors.redAccent;
static const Color addCartButtonColor = Colors.green;
static const Color buyButtonColor = Colors.red;
static const Color attributeTextColor = Colors.black54;
static const Color issueQuestionColor = Colors.black54;
static const Color issueAnswerColor = Colors.grey;
static const Color specificationWarpColor = Colors.redAccent;
}
icon.dart
import 'package:flutter/widgets.dart';
class KIcon{
static const String FONT_FAMILY = 'ShopICon';
static const IconData PASS_WORD = const IconData(0xe617, fontFamily: KIcon.FONT_FAMILY);
static const IconData ADDRESS=const IconData(0xe63c,fontFamily: KIcon.FONT_FAMILY);
static const IconData ORDER=const IconData(0xe634,fontFamily: KIcon.FONT_FAMILY);
static const IconData COLLECTION=const IconData(0xe61e,fontFamily: KIcon.FONT_FAMILY);
static const IconData ABOUT_US=const IconData(0xe654,fontFamily: KIcon.FONT_FAMILY);
}
string.dart
class KString {
static const String NO_DATA_TEXT = "暂无数据";
static const String NEW_PRODUCT = "新品";
static const String HOT_PRODUCT = "热卖产品";
static const String HOME = "首页";
static const String CATEGORY = "分类";
static const String SHOP_CAR = "购物车";
static const String MINE = "我的";
static const String SERVER_EXCEPTION = "请求网络数据异常";
static const String GOODS_DETAIL = "商品详情";
static const String GOODS_ATTRIBUTES = "商品属性";
static const String COMMON_PROBLEM = "常见问题";
static const String ADD_CART = "加入购物车";
static const String BUY = "立即购买";
static const String LOGIN = "登录";
static const String REGISTER = "注册";
static const String ACCOUNT_HINT = "请输入手机号码";
static const String PASSWORD_HINT = "请输入密码";
static const String ACCOUNT = "账号";
static const String PASSWORD = "密码";
static const String ACCOUNT_RULE = "账号必须为长度为11的数字";
static const String PASSWORD_RULE = "密码最少为6位";
static const String NOW_REGISTER = "马上注册";
static const String NICK_NAME = "NICK_NAME";
static const String HEAD_URL = "HEAD_URL";
static const String REGISTER_SUCCESS = "注册成功";
static const String PRICE = "价格";
static const String ALREAD_SELECTED = "已选择";
static const String SPECIFICATIONS = "规格";
static const String NUMBER = "数量";
static const String ISLOGIN = "isLogin";
static const String NICKNAME = "nickName";
static const String AVATARURL = "avatarUrl";
static const String LOGIN_SUCESS = "登录成功";
static const String SUCCESS = "success";
static const String ADD_CART_SUCCESS = "添加成功";
static const String CART = "购物车";
static const String TOTAL_MONEY = "共计";
static const String EDIT = "编辑";
static const String COMPLETE = "完成";
static const String DELETE = "删除";
static const String BUY_NOW = "下单";
static const String ORDER = "我的订单";
static const String ADDRESS = "地址管理";
static const String COLLECTION = "收藏";
static const String ABOUT_US = "关于我们";
static const String CLICK_LOGIN = "点击登录";
static const String SETTLEMENT = "结算";
static const String TIPS = "提示";
static const String DELETE_CART_ITEM_TIPS = "是否确认删除?";
static const String CONFIRM = "确认";
static const String CANCEL = "取消";
static const String DELETE_SUCCESS = "删除成功";
static const String FILL_IN_ORDER = "填写订单";
static const String DEFAULT = "默认";
static const String REMARK = "备注";
static const String GOODS_TOTAL = "商品合计";
static const String FREIGHT = "运费";
static const String PAY = "付款";
static const String MY_ADDRESS = "我的收货地址";
static const String ADD_ADDRESS = "添加新地址";
static const String IS_DEFAULT = "默认";
static const String ADDRESS_EDIT = "编辑";
static const String ADDRESS_EDIT_TITLE = "编辑地址";
static const String ADDRESS_PLEASE_INPUT_NAME = "请输入联系人姓名";
static const String ADDRESS_PLEASE_INPUT_PHONE = "请输入联系人电话";
static const String ADDRESS_PLEASE_SELECT_CITY = "请选择地址";
static const String ADDRESS_PLEASE_INPUT_DETAIL = "请输入详细地址如街道、楼栋房号等";
static const String ADDRESS_SET_DEFAULT = "设为默认地址";
static const String ADDRESS_DELETE = "删除收货地址";
static const String SUBMIT = "提交";
static const String SUBMIT_SUCCESS = "提交成功";
static const String ADDRESS_DELETE_SUCCESS = "删除成功";
static const String PLEASE_SELECT_ADDRESS = "请选择收货地址";
static const String MINE_COLLECT = "我的收藏";
static const String MINE_CANCEL_COLLECT = "是否确定取消收藏此商品?";
static const String MINE_ABOUT_US = "关于我们";
static const String MINE_ABOUT_US_CONTENT = "FlutterShop";
static const String MINE_ABOUT_NAME_TITLE = "公司名称";
static const String MINE_ABOUT_NAME = "Flutter";
static const String MINE_ABOUT_EMAIL_TITLE = "邮箱";
static const String MINE_ABOUT_EMAIL = "flutter@gmail.com";
static const String MINE_ABOUT_TEL_TITLE = "联系电话";
static const String MINE_ABOUT_TEL = "400-100-100";
static const String MINE_ORDER = "我的订单";
static const String HOME_TITLE = "首页";
static const String CATEGORY_TITLE = "分类";
static const String MINE_ORDER_TOTAL_GOODS = "共计";
static const String MINE_ORDER_GOODS_TOTAL = "件商品,";
static const String MINE_ORDER_PRICE = "合计¥";
static const String MINE_ORDER_SN = "订单编号:";
static const String MINE_ORDER_DETAIL = "订单详情";
static const String MINE_ORDER_TIME = "订单时间";
static const String ORDER_INFORMATION = "商品信息";
static const String DOLLAR = "¥";
static const String MINE_ORDER_DETAIL_TOTAL = "商品合计";
static const String MINE_ORDER_DETAIL_PAYMENTS = "实付";
static const String MINE_ORDER_DELETE_SUCCESS = "删除成功";
static const String MINE_ORDER_CANCEL_SUCCESS = "取消成功";
static const String MINE_ORDER_DELETE_TIPS = "是否确认删除此订单";
static const String MINE_ORDER_CANCEL_TIPS = "是否确认取消此订单";
static const String MINE_ORDER_ALREADY_CANCEL = "已取消";
static const String PLEASE_LOGIN = "请先登录";
static const String LOADING = "正在加载中...";
static const String TOKEN = "X-Shop-Token";
static const String LOGIN_OUT = "退出登录";
static const String LOGIN_OUT_TIPS="是否确认退出当前账号";
static const String ORDER_TITLE = "订单";
}
server_url.dart
class ServerUrl {
static const String BASE_URL = 'http://172.18.1.64:8080/client';
static const String HOME_URL = BASE_URL+'/home/index';
static const String CATEGORY_FIRST = BASE_URL+'/catalog/getfirstcategory';
static const String CATEGORY_SECOND = BASE_URL+'/catalog/getsecondcategory';
static const String GOODS_CATEGORY = BASE_URL+"/goods/category";
static const String GOODS_LIST = BASE_URL+'/goods/list';
static const String GOODS_DETAILS_URL = BASE_URL+'/goods/detail';
static const String REGISTER = BASE_URL+'/auth/register';
static const String LOGIN = BASE_URL+'/auth/login';
static const String LOGIN_OUT = BASE_URL+"/auth/logout";
static const String CART_ADD = BASE_URL+'/cart/add';
static const String CART_LIST = BASE_URL+'/cart/index';
static const String CART_UPDATE = BASE_URL+'/cart/update';
static const String CART_DELETE = BASE_URL+'/cart/delete';
static const String CART_CHECK = BASE_URL+'/cart/checked';
static const String CART_BUY = BASE_URL+'/cart/checkout';
static const String FAST_BUY = BASE_URL+'/cart/fastadd';
static const String ADDRESS_LIST = BASE_URL+'/address/list';
static const String ADDRESS_SAVE = BASE_URL+'/address/save';
static const String ADDRESS_DELETE = BASE_URL+'/address/delete';
static const String ADDRESS_DETAIL = BASE_URL+'/address/detail';
static const String COLLECT_LIST = BASE_URL+ '/collect/list';
static const String COLLECT_ADD_DELETE = BASE_URL+ '/collect/addordelete';
static const String ORDER_SUBMIT = BASE_URL+ '/order/submit';
static const String ORDER_LIST = BASE_URL+'/order/list';
static const String ORDER_DETAIL = BASE_URL+"/order/detail";
static const String ORDER_CANCEL = BASE_URL+"/order/cancel";
static const String ORDER_DELETE = BASE_URL+"/order/delete";
}
index.dart
export 'color.dart';
export 'icon.dart';
export 'string.dart';
export 'server_url.dart';
三、配置工具类
新建utils string_util.dart
import 'dart:convert';
class StringUtil {
static String encode(String originalCn) {
return jsonEncode(Utf8Encoder().convert(originalCn));
}
static String decode(String encodeCn) {
var list = List<int>();
jsonDecode(encodeCn).forEach(list.add);
String value = Utf8Decoder().convert(list);
return value;
}
}
fluro_convert_util.dart
import 'dart:convert';
class FluroConvertUtil{
static String objectToString<T>(T t) {
return fluroCnParamsEncode(jsonEncode(t));
}
static Map<String, dynamic> stringToMap(String str) {
return json.decode(fluroCnParamsDecode(str));
}
static String fluroCnParamsEncode(String originalCn) {
return jsonEncode(Utf8Encoder().convert(originalCn));
}
static String fluroCnParamsDecode(String encodeCn) {
var list = List<int>();
jsonDecode(encodeCn).forEach(list.add);
String value = Utf8Decoder().convert(list);
return value;
}
}
navigatr_util.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:myshop_flutter/router/application.dart';
import 'package:myshop_flutter/router/routers.dart';
import 'package:myshop_flutter/utils/fluro_convert_util.dart';
import 'package:myshop_flutter/utils/string_util.dart';
class NavigatorUtil {
static goShopMainPage(BuildContext context) {
Application.router.navigateTo(
context,
Routers.home,
transition: TransitionType.inFromRight, replace: true);
}
static goCategoryGoodsListPage(BuildContext context, String categoryName, int categoryId) {
var categoryNameText = StringUtil.encode(categoryName);
Application.router.navigateTo(
context,
Routers.categoryGoodsList + "?categoryName=$categoryNameText&categoryId=$categoryId",
transition: TransitionType.inFromRight);
}
static goRegister(BuildContext context) {
Application.router.navigateTo(context, Routers.register,
transition: TransitionType.inFromRight);
}
static goLogin(BuildContext context) {
Application.router.navigateTo(context, Routers.login,
transition: TransitionType.inFromRight);
}
static goGoodsDetails(BuildContext context, int goodsId) {
Application.router.navigateTo(
context, Routers.goodsDetail + "?goodsId=$goodsId",
transition: TransitionType.inFromRight);
}
static popRegister(BuildContext context) {
Application.router.pop(context);
}
static goFillInOrder(BuildContext context,int cartId) {
Application.router.navigateTo(
context,
Routers.fillInOrder+"?cartId=$cartId",
transition: TransitionType.inFromRight);
}
static Future goAddress(BuildContext context) {
return Application.router.navigateTo(context, Routers.address,
transition: TransitionType.inFromRight);
}
static Future goAddressEdit(BuildContext context, int addressId) {
return Application.router.navigateTo(
context,
Routers.addressEdit + "?addressId=$addressId",
transition: TransitionType.inFromRight);
}
static goCollect(BuildContext context) {
Application.router.navigateTo(context, Routers.mineCollect,
transition: TransitionType.inFromRight);
}
static goAboutUs(BuildContext context) {
Application.router.navigateTo(context, Routers.aboutUs,
transition: TransitionType.inFromRight);
}
static goOrder(BuildContext context) {
Application.router.navigateTo(context, Routers.mineOrder,
transition: TransitionType.inFromRight);
}
static Future goOrderDetail(BuildContext context, int orderId, String token) {
return Application.router.navigateTo(
context, Routers.mineOrderDetail + "?orderId=$orderId&token=$token",
transition: TransitionType.inFromRight);
}
static goWebView(BuildContext context, String title, String url) {
var titleName = FluroConvertUtil.fluroCnParamsEncode(title);
var urlEncode = FluroConvertUtil.fluroCnParamsEncode(url);
Application.router.navigateTo(
context, Routers.webView + "?title=$titleName&&url=$urlEncode",
transition: TransitionType.inFromRight);
}
static goBrandDetail(BuildContext context, String titleName, int id) {
var title = FluroConvertUtil.fluroCnParamsEncode(titleName);
Application.router.navigateTo(
context, Routers.brandDetail + "?titleName=$title&id=$id",
transition: TransitionType.inFromRight);
}
}
在yaml文件添加
#网络请求
dio: ^4.0.0
http_util.dart
import 'package:dio/dio.dart';
import 'package:myshop_flutter/config/index.dart';
import 'package:myshop_flutter/utils/shared_preferences_util.dart';
var dio;
class HttpUtil {
static HttpUtil get instance => _getInstance();
static HttpUtil _httpUtil;
static HttpUtil _getInstance() {
if (_httpUtil == null) {
_httpUtil = HttpUtil();
}
return _httpUtil;
}
HttpUtil() {
BaseOptions options = BaseOptions(
connectTimeout: 5000,
receiveTimeout: 5000,
);
dio = Dio(options);
Dio tokenInter(){
dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions options,handel) async {
print("========================请求数据===================");
print("url=${options.uri.toString()}");
print("params=${options.data}");
dio.lock();
await SharedPreferencesUtil.getToken().then((token) {
options.headers[KString.TOKEN] = token;
});
dio.unlock();
return options;
}, onResponse: (Response response,handel) {
if(response==null){
print("null");
}
print("========================请求数据===================");
print("code=${response.statusCode}");
print("response=${response.data}");
}, onError: (DioError error,w) {
print("========================请求错误===================");
print("message =${error.message}");
}));
}
}
Future get(String url, {Map<String, dynamic> parameters, Options options}) async {
Response response;
if (parameters != null && options != null) {
response = await dio.get(url, queryParameters: parameters, options: options);
} else if (parameters != null && options == null) {
response = await dio.get(url, queryParameters: parameters);
} else if (parameters == null && options != null) {
response = await dio.get(url, options: options);
} else {
response = await dio.get(url);
}
return response.data;
}
Future post(String url, {Map<String, dynamic> parameters, Options options}) async {
Response response;
if (parameters != null && options != null) {
response = await dio.post(url, data: parameters, options: options);
} else if (parameters != null && options == null) {
response = await dio.post(url, data: parameters);
} else if (parameters == null && options != null) {
response = await dio.post(url, options: options);
} else {
response = await dio.post(url);
}
return response.data;
}
}
四、ui加载页面
画出根路由页面
import 'package:flutter/material.dart';
import 'package:myshop_flutter/utils/navigator_util.dart';
class LoadingPage extends StatefulWidget {
@override
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<LoadingPage> {
@override
void initState() {
super.initState();
Future.delayed(Duration(seconds: 3), () {
NavigatorUtil.goShopMainPage(context);
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: Image.asset(
"images/loading.png",
width: double.infinity,
height: double.infinity,
fit: BoxFit.fill,
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:myshop_flutter/config/index.dart';
import '../CartPage/CartPage.dart';
import '../CategoryPage/CategoryPage.dart';
import 'package:myshop_flutter/page/home/HomePage.dart';
import '../Mine/MinePage.dart';
class HomeIndexPage extends StatefulWidget {
const HomeIndexPage({Key key}) : super(key: key);
@override
_HomeIndexPageState createState() => _HomeIndexPageState();
}
class _HomeIndexPageState extends State<HomeIndexPage> {
int _selectedIndex = 0;
List<Widget> _list = List();
@override
void initState() {
super.initState();
_list
..add(HomePage())
..add(CategoryPage())
..add(CartPage())
..add(MinePage());
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _list,
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
selectedItemColor: KColor.indexTabSelectedColor,
unselectedItemColor: KColor.indexTabUnSelectedColor,
currentIndex: _selectedIndex,
onTap: _onItemTapped,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text(KString.HOME),
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
title: Text(KString.CATEGORY),
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
title: Text(KString.SHOP_CAR),
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text(KString.MINE),
),
],
),
);
}
_onItemTapped(int index) {
setState(() {
this._selectedIndex = index;
});
}
}
|