通过2周的学习,看过笔记1-8的小伙伴们已经有很多开始本身写APP了,我也按耐不住这股热情,想要本身开发个APP玩玩,so,从本篇起,仿造一个APP,项目从0开始,每篇增长一些内容,一点一点完成这个APP,每次迭代的代码都将上传到个人git仓库。html
鉴于我2周多的Flutter代码经验,代码结构的思惟可能没有多年开发经验的老鸟稳,若是有写的很差的地方请你们多多指教。前端
如上图所示, 本篇将搭建一个HomePage,再其左上角加入侧边栏入口,而且经过侧边栏能够进入其余页面。vue
##第一步 建立项目和文件夹。打开vscode,到一个路径下输入命令:react
flutter create appbyfluttergit
根据图中所示,将项目目录准备好: 程序员
因为第一篇开发用到的东西很少,先简单向项目目录中添加一个images文件,用于存放APP默认图片。默认的lib文件夹下添加一个pages文件夹,用于存放每一个页面。github
##第二步 将main.dart仅做为APP的入口,承担页面入口和路由的功能: web
因为APP不仅有一个页面,为了方便维护和管理,全部的页面代码都转移到pages文件夹下,main.dart中处理APP的主页面入口、路由和一系列须要初始化(如自动登录、入场动画等)的任务。有过vue、react开发经验的前端大神们应该不陌生,这样作可使主程序和页面解耦,固然本篇尚未用到路由,暂不书写路由的代码,等不及要了解路由的同窗能够参考前端高手偏罗的第一个APP或者英文阅读理解。网络
##第三步 ###主页面 如第一步的图所示,在pages文件夹中添加了2个文件:home_page.dart和other_page.dart,其中home_page.dart是这个APP的主页面,other_page.dart做为的之后再开发的页面。app
注意在第二步的runapp()
函数中,用到了MaterialApp()
,意味着程序APP全部的页面控件默认配套_Material_风格。
因为主页面会动态引用各类控件,所以_StatefulWidget_类型才能够知足页面需求。从下图中分解一下页面结构:
先看图左中有状态控件HomePage
为整个页面的最顶层包裹,其内放入了一个Scaffold
脚手架,Scaffold
中有很是丰富的属性,能够放入侧边栏按钮Drawer
控件、页面标题AppBar
控件和body
部分,因而贴入如下代码:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("CYC"), backgroundColor: Colors.redAccent,), //头部的标题AppBar
drawer: new Drawer(), //侧边栏按钮Drawer
body: new Center( //中央内容部分body
child: new Text('HomePage',style: new TextStyle(fontSize: 35.0),),
),
);
}
}
复制代码
OK,左图的页面就这么轻松搭建完毕。要实现右图中的展开的侧边栏,很简单,向Drawer
控件中塞东西吧。
###侧边栏 咱们先图解一下侧边栏的结构:
整个侧边栏主从上到下按区块分别放置了帐号和若干功能项+分割线的列表,很容易想到使用布局控件ListView
。
帐号信息区域中有帐号头像、粉丝头像、帐号文字信息和背景图,这块咱们可使用Material控件库的UserAccountsDrawerHeader
控件实现。
下面的功能列表项目不用多说,ListTitle
控件妥妥的,分割线直接Divider
便可。
因而,咱们向new Drawer()
中加入以下代码:
//侧边栏填充内容
drawer: new Drawer( //侧边栏按钮Drawer
child: new ListView(
children: <Widget>[
new UserAccountsDrawerHeader( //Material内置控件
accountName: new Text('CYC'), //用户名
accountEmail: new Text('example@126.com'), //用户邮箱
currentAccountPicture: new GestureDetector( //用户头像
onTap: () => print('current user'),
child: new CircleAvatar( //圆形图标控件
backgroundImage: new NetworkImage('https://upload.jianshu.io/users/upload_avatars/7700793/dbcf94ba-9e63-4fcf-aa77-361644dd5a87?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240'),//图片调取自网络
),
),
otherAccountsPictures: <Widget>[ //粉丝头像
new GestureDetector( //手势探测器,能够识别各类手势,这里只用到了onTap
onTap: () => print('other user'), //暂且先打印一下信息吧,之后再添加跳转页面的逻辑
child: new CircleAvatar(
backgroundImage: new NetworkImage('https://upload.jianshu.io/users/upload_avatars/10878817/240ab127-e41b-496b-80d6-fc6c0c99f291?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240'),
),
),
new GestureDetector(
onTap: () => print('other user'),
child: new CircleAvatar(
backgroundImage: new NetworkImage('https://upload.jianshu.io/users/upload_avatars/8346438/e3e45f12-b3c2-45a1-95ac-a608fa3b8960?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240'),
),
),
],
decoration: new BoxDecoration( //用一个BoxDecoration装饰器提供背景图片
image: new DecorationImage(
fit: BoxFit.fill,
// image: new NetworkImage('https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/lakes/images/lake.jpg')
//能够试试图片调取自本地。调用本地资源,须要到pubspec.yaml中配置文件路径
image: new ExactAssetImage('images/lake.jpg'),
),
),
),
new ListTile( //第一个功能项
title: new Text('First Page'),
trailing: new Icon(Icons.arrow_upward),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new SidebarPage()));
}
),
new ListTile( //第二个功能项
title: new Text('Second Page'),
trailing: new Icon(Icons.arrow_right),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new SidebarPage()));
}
),
new ListTile( //第二个功能项
title: new Text('Second Page'),
trailing: new Icon(Icons.arrow_right),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).pushNamed('/a');
}
),
new Divider(), //分割线控件
new ListTile( //退出按钮
title: new Text('Close'),
trailing: new Icon(Icons.cancel),
onTap: () => Navigator.of(context).pop(), //点击后收起侧边栏
),
],
),
)
复制代码
上面的代码,用到了不少陌生的控件,如UserAccountsDrawerHeader、GestureDetector、BoxDecoration、NetworkImage、ExactAssetImage等等,这里我就不一一介绍了,各自的特性和用法请参考官方阅读理解题库,刚开始我也是懵逼的,这些内置控件你们简单背诵一下便可,有可能后面由于页面复杂度的提升,单独拿出来封装也说不定,会使用就能够了。
你们能够试试从屏幕的左边沿向右滑动的手势,是否是发现能够拉出侧边栏?再向右滑动收回侧边栏。我并无添加任何手势事件的代码,这是
Drawer
控件自带的属性,和控件自带Material风格动效同样,内置控件也自带了默认手势,隐隐听到~原生开发的程序员哭晕在厕所,哈哈哈
##第四步 ###功能按钮触发页面跳转。 首先咱们要建立一个子页面,因而乎pages文件夹下,我又建立了一个other_page.dart文件。要从HomePage.dart中跳转到other_page.dart,还须要在HomePage.dart中引一下other_page.dart。因而:
而后到other_page.dart中敲入代码:
import 'package:flutter/material.dart';
class OtherPage extends StatelessWidget {
final String pageText; //定义一个常量,用于保存跳转进来获取到的参数
OtherPage(this.pageText); //构造函数,获取参数
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text(pageText),), //将参数看成页面标题
body: new Center(
child: new Text('pageText'),
),
);
}
}
复制代码
Flutter要求转入的页面必须提早定义一个常量分配好空间,且在构造函数中植入这个参数,才可捕捉外部传过来的参数值。
###触发跳转 向First Page和Second Page这两个ListTile
控件中加入点击跳转页面的代码:
new ListTile(
title: new Text('First Page'),
trailing: new Icon(Icons.arrow_upward),
onTap: () {
Navigator.of(context).pop(); //点击后收起侧边栏
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new OtherPage('First Page'))); //进入OtherPage页面,传入参数First Page
}
),
new ListTile(
title: new Text('Second Page'),
trailing: new Icon(Icons.arrow_right),
onTap: () {
Navigator.of(context).pop();
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new OtherPage('Second Page')));
}
),
复制代码
上面的代码中onTap()
事件里有一句Navigator.of(context).pop();
,意味着先收起侧边栏,再进入新页面。若是没有这句代码,即便进入了新页面,再返回来,侧边栏依然处于展开的样子,这个体验是反人类的,因此写上它吧~少年。
##总结 因为我没有详细的去定位和设计产品究竟是干什么的,你们可能会以为有点懵逼,为何是这种侧边栏的布局,而不是不少社交APP经常使用的顶部+底部Tab栏的样式,不着急,咱们下一篇实现。侧边栏有什么好处呢?节省空间,若是底部须要放置更重要的功能控件(好比音乐播放器)时,往侧边栏放入页面切换逻辑是个不错的应对方案。本篇内容其实很是简单,主要就是介绍你们认识几个经常使用控件,不用调CSS,不用思考由于冒泡事件致使复杂的交互逻辑实现,这就是Flutter的魅力,简约而不简单,相信你们看过以后,自行开发APP的信心更足了,好勒,今天就到这里,感谢你们的支持,请关注个人Flutter圈子,多多投稿,也能够加入**flutter 中文社区(官方QQ群:338252156)**共同成长,谢谢你们~