flutter实战 开发商城 (含数据库、接口(一)
这文我们一步一步开发一个商城。首先我们设定的目标是完成下面5个页面。为了完成这个炫酷的任务我们先看下你需要哪些知识。注意葵花宝典第一页:欲练神功,必先。。。学会下图知识:不要被这个图吓到。第二页告诉你:如不自攻,亦能成功。。先列举两个会用到的插件:Dio2.0:Dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、...
这文我们一步一步开发一个商城。首先我们设定的目标是完成下面5个页面。
为了完成这个炫酷的任务我们先看下你需要哪些知识。注意葵花宝典第一页:欲练神功,必先。。。学会下图知识:
不要被这个图吓到。第二页告诉你:如不自攻,亦能成功。。
先列举两个会用到的插件:
-
Dio2.0:
Dio
是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消等操作。视频中将全面学习和使用Dio的操作。 -
Swiper:swiper滑动插件的使用,使用Swiper插件图片的切换效果
第一步:先打开VSCode,文件打开一个自己的目录。例如我的D:\flutter\App,开启终端,输入flutter create flutter_shop;
如果出错,你可能没配置好fultter环境。这个问题这里不说了。
然后进到这个目录中。运行看下。测试自己环境没问题。
看看这破电脑,竟然用了1分多钟。
下面我们开始一个页面:在lib下建立pages/index_page.dart,这也是一个测试页面,页面只有一个标题和中间有个文字。
import 'package:flutter/material.dart';
class IndexPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('百姓生活+'),),
body: Center(
child:Text(' 百姓生活+')
),
);
}
}
然后修改flutter-shop下的main.dart,引入我们写的这个测试文件
import 'package:flutter/material.dart';
import './pages/index_page.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: MaterialApp(
title:'百姓生活+',
debugShowCheckedModeBanner: false, //Flutter去除右上角Debug标签
theme: ThemeData(
primaryColor:Colors.pink
),
home:IndexPage()
),
);
}
}
然后运行 flutter run ,效果如下:
修改刚刚的index_page.dart,加入一个导航条。如下代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'home_page.dart';
import 'category_page.dart';
import 'cart_page.dart';
import 'member_page.dart';
class IndexPage extends StatefulWidget {
@override
_IndexPageState createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
final List<BottomNavigationBarItem> bottomTabs = [
BottomNavigationBarItem(icon: Icon(CupertinoIcons.home), title: Text('首页')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.search), title: Text('分类')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.shopping_cart), title: Text('购物车')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.profile_circled), title: Text('会员中心'))
];
final List tabBodies = [HomePage(), CategoryPage(), CartPage(), MemberPage()];
int currentIndex = 0;
var currentPage;
@override
void initState() {
super.initState();
currentPage = tabBodies[currentIndex];
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(244, 245, 245, 1.0),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
items: bottomTabs,
onTap: (index) {
setState(() {
currentIndex = index;
currentPage = tabBodies[currentIndex];
});
},
),
body: currentPage,
);
}
}
另外新建4个文件:类似下面的代码,注意修改类名。和Text内容以示区别。
import 'package:flutter/material.dart';
class MemberPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body:Center(
child: Text('MemberPage'),
)
);
}
}
这样导航条就做好了,点击分类会变化页面。
接下来添加 dio插件:
修改pages/home_page.dart
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
getHttp();
return Scaffold(
body:Center(
child: Text('商城首页'),
)
);
}
}
void getHttp()async{
try{
Response response;
var data={'name':'Jack'};
response = await Dio().get(
'http://www.cctv.com/'
);
return print(response);
}catch(e){
return print(e);
}
}
好了,dio开始工作了。下面我们做一个页面传递参数,然后进行一个Post请求。
main.dart:入口文件一般不用怎么修改。
import 'package:flutter/material.dart';
import './pages/index_page.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: MaterialApp(
title:'百姓生活+',
debugShowCheckedModeBanner: false, //Flutter去除右上角Debug标签
theme: ThemeData(
primaryColor:Colors.pink
),
home:IndexPage()
),
);
}
}
pages/index_page.dart ,框架文件,定义了下方的导航Bar,并引入4个页面文件。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'home_page.dart';
import 'category_page.dart';
import 'cart_page.dart';
import 'member_page.dart';
class IndexPage extends StatefulWidget {
@override
_IndexPageState createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
final List<BottomNavigationBarItem> bottomTabs = [
BottomNavigationBarItem(icon: Icon(CupertinoIcons.home), title: Text('首页')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.search), title: Text('分类')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.shopping_cart), title: Text('购物车')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.profile_circled), title: Text('会员中心'))
];
final List tabBodies = [HomePage(), CategoryPage(), CartPage(), MemberPage()];
int currentIndex = 0;
var currentPage;
@override
void initState() {
super.initState();
currentPage = tabBodies[currentIndex];
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(244, 245, 245, 1.0),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
items: bottomTabs,
onTap: (index) {
setState(() {
currentIndex = index;
currentPage = tabBodies[currentIndex];
});
},
),
body: currentPage,
);
}
}
4个页面文件:/pages/home_page.dart:
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController typeController = TextEditingController();
String showText = '天气会显示在这里';
@override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
appBar: AppBar(title: Text('天气API测试'),),
body:Container(
height: 1000,
child: Column(
children: <Widget>[
TextField(
controller:typeController,
decoration:InputDecoration (
contentPadding: EdgeInsets.all(10.0),
labelText: '输入城市',
helperText: '请输入你的城市'
),
autofocus: false,
),
RaisedButton(
onPressed:_choiceAction,
child: Text('查询'),
),
Text(
showText,
overflow:TextOverflow.ellipsis,
maxLines: 2,
),
],
),
)
),
);
}
Future getHttp(String TypeText)async{
try{
Response response;
var data={'name':TypeText};
response = await Dio().get(
'https://api.heweather.net/s6/weather/now?location=beijing&key=55799160534d495a81c373e69fcf9366',
queryParameters:data
);
return response.data;
}catch(e){
return print(e);
}
}
void _choiceAction(){
if(typeController.text.toString()==''){
showDialog(
context: context,
builder: (context)=>AlertDialog(title:Text('城市地址不能为空'))
);
}else{
getHttp(typeController.text.toString()).then((val){
setState(() {
// showText=val['data']['name'].toString();
showText=val.toString();
});
});
}
}
}
其他3个文件暂不做修改:类似这样,类名不同而已。
import 'package:flutter/material.dart';
class CartPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body:Center(
child: Text('Cart首页'),
)
);
}
}
测试结果:如下,你成功了吗?
4
接下来,我们这里稍作修改:把接口地址写在一个单独的文件里,如
/config/service_url.dart:
const serviceUrl= 'http://www.xxxxx.com';//此端口后台写的。
const servicePath={
'homePageContext': serviceUrl+'/house/indexapi', // 商家首页信息
};
/service/service_method.dart:
import 'package:dio/dio.dart';
import 'dart:async';
// import 'dart:io';
import '../config/service_url.dart';
Future getHomePageContent() async {
try {
print('start get HomePage data.....');
Response response;
Dio dio = new Dio();
// dio.options.contentType("application/x-www-form-urlencoded") ;
var fromData = {'Sokey': ''};
response = await dio.post(servicePath['homePageContext'], data: fromData);
if (response.statusCode == 200) {
return response.data;
} else {
throw Exception('后端接口异常!');
}
} catch (e) {
return print('ERROR:======>' + e);
}
}
index
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'home_page.dart';
import 'category_page.dart';
import 'cart_page.dart';
import 'member_page.dart';
class IndexPage extends StatefulWidget {
@override
_IndexPageState createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
final List<BottomNavigationBarItem> bottomTabs = [
BottomNavigationBarItem(icon: Icon(CupertinoIcons.home), title: Text('首页')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.search), title: Text('分类')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.shopping_cart), title: Text('购物车')),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.profile_circled), title: Text('会员中心'))
];
final List tabBodies = [HomePage(), CategoryPage(), CartPage(), MemberPage()];
int currentIndex = 0;
var currentPage;
@override
void initState() {
super.initState();
currentPage = tabBodies[currentIndex];
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(244, 245, 245, 1.0),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
items: bottomTabs,
onTap: (index) {
setState(() {
currentIndex = index;
currentPage = tabBodies[currentIndex];
});
},
),
body: currentPage,
);
}
}
home:
import 'package:flutter/material.dart';
import '../service/service_method.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String homePageContent = '正在获取数据';
@override
void initState() {
getHomePageContent().then((val){
setState((){
homePageContent=val.toString();
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("百姓生活+"),),
body: SingleChildScrollView(child: Text(homePageContent),),
);
}
}
其他文件几乎没变化。结果首页会获取到数据
接下来我们获取轮播图数据,然后显示一个轮播图。首先是放个插件。
然后修改Home.dart:
import 'package:flutter/material.dart';
import '../service/service_method.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'dart:convert';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("百姓生活+"),),
body:FutureBuilder(
future: getHomePageContent(),
builder: (context,snapshot){
if (snapshot.hasData) {
// var d = {"list":[ {"id":3409,"KP_Wjt":"http:\/\/ .com\/uploads\/20191101\/3878bfd44de3de2cd9549fcf53d063b2Cen.jpg","KP_LpName":"港珠澳ISC首座","KP_KfID":"9","Kp_gflm":1,"KP_City":292,"KP_Tel":"400-6885-919","KP_Fjh":"","KP_Xszt":0,"KP_Wylx":"写字楼","KP_TsType":"养生社区,宜居生态地产","KP_Lpdz":"珠海市横琴大桥旁·宝湾路与富林东路交汇处","KP_YouHui":"全款99折","KP_TaoJia":"","KP_Tj":0,"KP_Yhz":0,"KP_Zlhx":"","KP_AllViewUrl":"","KP_Isallview":0,"KP_Qiprice":24000,"KP_Juprice":25000,"KP_ValidityStart":"2019年11月01日","KP_ValidityEnd":"2019年11月30日","KP_Kefu_Pic":"http:\/\/yuefangwangimg.oss-cn-hangzhou.aliyuncs.com\/uploads\/20190730\/505ff8f37977274e223423c0804514421Max.jpg","KP_Kefu_Name":"吴谊兰","CNAME":"珠海市","isvideo":0,"dtone":{"id":41803,"KP_Title":"珠海港珠澳ISC首座项目均价25000元\/㎡,非毛坯交付"}}],"total":3732};
var e = json.encode(snapshot.data );
var data=json.decode(e.toString());
List<Map> swiperDataList = (data['list'] as List).cast(); // 顶部轮播组件数
//print(swiperDataList);
return Column(children: <Widget>[
SwiperDiy(swiperDataList:swiperDataList)
],);
} else {
return Center(child: Text('Loading....'),);
}
},
)
);
}
}
// 首页轮播组件编写
class SwiperDiy extends StatelessWidget {
final List swiperDataList;
SwiperDiy({Key key,this.swiperDataList}):super(key:key);
@override
Widget build(BuildContext context) {
return Container(
height: 333.0,
child: Swiper(
itemBuilder: (BuildContext context,int index){
return Image.network("${swiperDataList[index]['KP_Wjt']}",fit:BoxFit.fill);
},
itemCount: swiperDataList.length,
pagination: new SwiperPagination(),
autoplay: true,
),
);
}
}
结果如下:
谁家发生这个事,都会崩溃了。。这个社会要整顿了。。。。
下节我会公布我的接口数据。你不会头疼了。
更多推荐
所有评论(0)