flutter项目实战
学习完基础知识之后,通过一个旅游的demo app来实践flutter的开发技能
项目代码地址:https://github.com/shengshunyan/my_flutter_app.git
项目结构
- images/ 存放项目图片 
- pubspec.yaml 项目配置文件(依赖保,静态资源配置等) 
- lib/ 项目代码 - model/ 接口的数据模型
- dao/ 获取接口数据的服务层
- pages/ 页面模块
- widget/ 公共组件
- util/ 公共方法
- navigator/ 导航
- main.dart 主入口文件
 
导航
- 用PageView组件来控制页面模块的切换,PageView组件有相关的优化
dart
| 1 | Scaffold( | 
首页
- MediaQuery.removePadding可用于移除ListView顶部预设的padding dart- 1 
 2
 3
 4
 5- MediaQuery.removePadding( 
 context: context,
 removeTop: true,
 child: ...
 }
- RefreshIndicator组件可实现下拉刷新功能 dart- 1 
 2
 3
 4- RefreshIndicator( 
 onRefresh: loadData,
 child: ...
 )
- NotificationListener组件可以监听页面的上下滚动 dart- 1 
 2
 3
 4
 5
 6- NotificationListener( 
 onNotification: (scrollNotification) {
 // ...
 },
 child: ...,
 )
- ListView组件可以用于一个从上到下的模块内容展示 dart- 1 
 2
 3
 4
 5
 6- ListView( 
 children: <Widget>[
 widget_1,
 widget_2,
 ]
 )
- 页面的跳转 dart- 1 
 2
 3- Navigator.push(context, MaterialPageRoute(builder: (context) { 
 return SpeakPage();
 }));
- 根据loading状态,展示页面加载中样式 dart- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 Widget build(BuildContext context) {
 if (isLoading) {
 return Center(
 child: CircularProgressIndicator(),
 );
 }
 return child;
 }
- GestureDetector组件用于监听用户行为,比如点击 dart- 1 
 2
 3
 4
 5- GestureDetector( 
 onTap: () {
 // ...
 },
 child: ...
- Row用于横向展示元素,Column用于竖向展示元素(很常用) 
- 实现了一个WebView组件,用于app直接跳转h5页面,可以设置头部 dart- 1 
 2
 3
 4
 5
 6- WebView( 
 url: model.url,
 statusBarColor: model.statusBarColor,
 title: model.title,
 hideAppBar: model.hideAppBar,
 ));
搜索及语音页
- 继承自AnimatedWidget组件,实现了一个语音按钮的动画组件AnimatedMicdart1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30const double MIC_SIZE = 80; 
 class AnimatedMic extends AnimatedWidget {
 static final _opacityTween = Tween<double>(begin: 1, end: 0.5);
 static final _sizeTween = Tween<double>(begin: MIC_SIZE, end: MIC_SIZE - 20);
 AnimatedMic({Key key, Animation<double> animation})
 : super(key: key, listenable: animation);
 
 Widget build(BuildContext context) {
 final Animation<double> animation = listenable;
 return Opacity(
 opacity: _opacityTween.evaluate(animation),
 child: Container(
 height: _sizeTween.evaluate(animation),
 width: _sizeTween.evaluate(animation),
 decoration: BoxDecoration(
 color: Colors.blue,
 borderRadius: BorderRadius.circular(MIC_SIZE / 2),
 ),
 child: Icon(
 Icons.mic,
 color: Colors.white,
 size: 30,
 ),
 ),
 );
 }
 }
旅拍
- 利用TabBar组件实现一个头部横向的tab切换功能 dart- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17- TabBar( 
 controller: _controller,
 isScrollable: true,
 labelColor: Colors.black,
 labelPadding: EdgeInsets.fromLTRB(20, 0, 10, 5),
 indicator: UnderlineTabIndicator(
 borderSide: BorderSide(
 color: Color(0xff2fcfbb),
 width: 3,
 ),
 insets: EdgeInsets.only(bottom: 10)),
 tabs: tabs.map<Tab>((TravelTab tab) {
 return Tab(
 text: tab.labelName,
 );
 }).toList()
 )
- 没有预设宽度/高度时,Flexible组件可以使Row、Column、Flex等子组件在主轴方向有填充可用空间的能力,但是不强制子组件填充可用空间。 dart- 1 
 2
 3- Flexible( 
 child: ...
 )
- flutter_staggered_grid_view库的组件StaggeredGridView可用于grid布局的实现(瀑布流);还可利用controller属性监听上拉事件来实现上拉到底部加载更多;mixin AutomaticKeepAliveClientMixin组件来保持缓存各个tab页; dart- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53- class TravelTabPage extends StatefulWidget { 
 
 _TravelTabPageState createState() => _TravelTabPageState();
 }
 // 缓存各个tab页的内容(1) AutomaticKeepAliveClientMixin mixin
 class _TravelTabPageState extends State<TravelTabPage>
 with AutomaticKeepAliveClientMixin {
 // 用于上拉加载更多
 ScrollController _scrollController = ScrollController();
 
 void initState() {
 _loadData();
 // 上拉加载更多
 _scrollController.addListener(() {
 if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
 _loadData(loadMore: true);
 }
 });
 super.initState();
 }
 
 Widget build(BuildContext context) {
 return Scaffold(
 body: StaggeredGridView.countBuilder(
 controller: _scrollController,
 crossAxisCount: 4,
 itemCount: travelItems?.length ?? 0,
 itemBuilder: (BuildContext context, int index) =>
 _TravelItem(index: index, item: travelItems[index]),
 staggeredTileBuilder: (int index) => new StaggeredTile.fit(2),
 mainAxisSpacing: 4.0,
 crossAxisSpacing: 4.0,
 ),
 );
 }
 // 获取页面数据
 void _loadData({bool loadMore = false}) {
 // ...
 }
 // 缓存各个tab页的内容(2)
 
 bool get wantKeepAlive => true;
 Future<Null> _handleRefresh() async {
 _loadData();
 return null;
 }
 }
我的
我的 模块页面直接引用的h5页面
dart
| 1 | 
 | 








