上一章讲解了flutter的一些基础控件,这一样讲解一下网络请求,路由等内容。
一,网络请求
1,请求示例
在项目的pubspec.yaml中导入http库
dependencies:
flutter:
sdk: flutter
http: ^0.12.0 //http库
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
在body中引入一个HttpDemo,用来请求网络数据并且显示在页面上。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;//网络请求
import 'dart:convert';//json转换
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: HttpDemo(),//网络请求实现
),
theme: ThemeData(primarySwatch: Colors.lightBlue),
);
}
}
HttpDemo的实现部分,一个get请求,请求地址是豆瓣电影排行
class HttpDemo extends StatefulWidget {
@override
_HttpDemoState createState() => _HttpDemoState();
}
class _HttpDemoState extends State<HttpDemo> {
@override
void initState() {
// TODO: implement initState
super.initState();
fetchPost(); //请求
}
fetchPost() async {
final response = await http
.get('https://api.douban.com/v2/movie/top250?start=0&count=10');
print('statusCode=${response.statusCode}'); //请求状态码
print('body=${response.body}'); //请求实体
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container();
}
}
把请求后的状态码和数据打印出来
开始解析数据,用ListView显示出来,如下效果
修改HttpDemo代码如下:
class HttpDemo extends StatefulWidget {
@override
_HttpDemoState createState() => _HttpDemoState();
}
class _HttpDemoState extends State<HttpDemo> {
Future<List<MovieRank>> getMovie() async {
final response = await http
.get('https://api.douban.com/v2/movie/top250?start=0&count=20');
if (response.statusCode == 200) {
//请求成功
final body = json.decode(response.body);
List subjects = body['subjects'];
return subjects.map((item) => MovieRank.fromJson(item)).toList();
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return FutureBuilder(
future: getMovie(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Text('loading...'),
);
}
return ListView(
children: snapshot.data.map<Widget>((item) {
return Card(
child: Row(
children: <Widget>[
Image.network(
item.image,
height: 100,
width: 50,
),
Column(
crossAxisAlignment:CrossAxisAlignment.start,
children: <Widget>[
Text(
item.title,
style: TextStyle(
fontSize: 20.0,
color: Colors.black
),
),
Text(
'年代:${item.year}',
style: TextStyle(
fontSize: 16.0,
color: Colors.grey
),
)
],
)
],
),
);
}).toList(),
);
},
);
}
}
class MovieRank {
final String title; //电影名字
final String image; //电影图片
final String year; //年份
MovieRank(this.title, this.image, this.year);
MovieRank.fromJson(Map json)
: this.title = json['title'],
this.image = json['images']['small'],
this.year = json['year'];
}
在HttpDemo中使用了FutureBuilder,有关FutureBuilder讲解可以看FutureBuilder
二,路由
路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController。所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。这和原生开发类似,无论是Android还是iOS,导航管理都会维护一个路由栈,路由入栈(push)操作对应打开一个新页面,路由出栈(pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。
实现页面跳转关键代码,跳转到页面MyPage并且传入值。
Navigator.push(context,
MaterialPageRoute(
builder: (context) {
return MyPage();
}));
页面返回
Navigator.pop(context)
MaterialPageRoute 是Material组件库的一个Widget,它可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。
MaterialPageRoute 构造函数的各个参数的意义:
MaterialPageRoute({
WidgetBuilder builder,
RouteSettings settings,
bool maintainState = true,
bool fullscreenDialog = false,
})
- builder是一个WidgetBuilder类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个widget。
- settings 包含路由的配置信息,如路由名称、是否初始路由(首页)。
- maintainState:默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState为false。
- fullscreenDialog表示新的路由页面是否是一个全屏的模态对话框,在iOS中,如果fullscreenDialog为true,新页面将会从屏幕底部滑入(而不是水平方向)。
1,简单示例,实现路由切换页面
在首页放一个按钮,点击按钮跳转到另一个页面,路由跳转默认是有返回按钮的。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: new HomeDemo()
);
}
}
class HomeDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('首页'),
),
body: new Center(
child: new RaisedButton(
child: new Text('跳转'),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new RouteDemo()),
);
},
),
),
);
}
}
class RouteDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('路由页'),
),
body: new Center(
child: new RaisedButton(
child: new Text('返回'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
2,路由也可以指定名字
上边示例中在MyApp的MaterialApp中指定路由名称。
routes: {
"route_demo":(context)=>RouteDemo(),
},
把跳转按钮点击事件修改为
Navigator.pushNamed(context, "route_demo");
这样就可以通过指定路由名称进行跳转
三,动画
1,倒计时动画
class CountDown extends StatefulWidget {
@override
_CountDownState createState() => _CountDownState();
}
class _CountDownState extends State<CountDown>
with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation animation;
@override
void initState() {
super.initState();
animationController =
AnimationController(vsync: this, duration: Duration(seconds: 5));
animation = IntTween(begin: 5, end: 0).animate(
CurvedAnimation(parent: animationController, curve: Curves.ease));
}
@override
Widget build(BuildContext context) {
final double textSize = 56.0;
return Scaffold(
appBar: AppBar(
title: Text('倒计时'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedBuilder(animation: animationController,
builder: (BuildContext context, Widget child) {
return Text(animation.value.toString(),
style: TextStyle(fontSize: textSize),);
}),
RaisedButton(
child: Text("倒计时"),
onPressed: () {
animationController.forward();
}
),
],
),
),
);
}
}