创建Flutter项目有两种方式:通过命令行创建 和 通过开发工具创建
通过命令行创建非常简单,在终端输入以下命令即可:
**注意:**Flutter的名称不要包含特殊的字符,另外不可以使用驼峰标识
创建完之后使用自己喜欢的开发工具打开即可
flutter create learn_flutter
选择Start a new Flutter project,之后填写相关的信息即可,这里不再赘述
runApp是Flutter内部提供的一个函数,当我们启动一个Flutter应用程序时就是从调用这个函数开始的
我们学习Flutter,从一开始就可以有一个基本的认识:Flutter中万物皆Widget(万物皆可盘);
在我们iOS或者Android开发中,我们的界面有很多种类的划分:应用(Application)、视图控制器(View Controller)、活动(Activity)、View(视图)、Button(按钮)等等;
但是在Flutter中,这些东西都是不同的Widget而已;
也就是我们整个应用程序中所看到的内容几乎都是Widget,甚至是内边距的设置,我们也需要使用一个叫Padding的Widget来做;
runApp函数让我们传入的就是一个Widget:我们可以导入Flutter默认已经给我们提供的Material库,来使用其中的很多内置Widget;
修正:widget
flutter里面万物皆是winget,我们要想让文字居中,也是在外面加一个widget
修正:widget
material是Google公司推行的一套设计风格,或者叫设计语言、设计规范等;
里面有非常多的设计规范,比如颜色、文字的排版、响应动画与过度、填充等等;
在Flutter中高度集成了Material风格的Widget;
在我们的应用中,我们可以直接使用这些Widget来创建我们的应用(后面会用到很多);
我们可以使用Text小部件来完成文字的显示;
我们发现Text小部件继承自StatelessWidget,StatelessWidget继承自Widget;
所以我们可以将Text小部件传入到runApp函数中
属性非常多,但是我们已经学习了Dart语法,所以你会发现只有this.data属性是必须传入的。
正常的App页面应该有一定的结构,比如通常都会有导航栏,会有一些背景颜色等
在开发当中,我们并不需要从零去搭建这种结构化的界面,我们可以使用Material库,直接使用其中的一些封装好的组件来完成一些结构的搭建。
我们通过下面的代码来实现:
import 'package:flutter/material.dart';
main(List<String> args) {
runApp(
debugShowCheckedModeBanner: false,//取消debug显示
MaterialApp( //传入一个material风格的widget
home: Scaffold(//material有一个可选参数 home
appBar: AppBar(
title: Text("CODERWHY"),
),
body: Center(
child: Text(
"Hello World",
//textDirection: TextDirection.ltr, 可以省略,Material风格默认设置文字排版风格
style: TextStyle(fontSize: 36),
),
),
),
)
);
}
在最外层包裹一个MaterialApp
这意味着整个应用我们都会采用MaterialApp风格的一些东西,方便我们对应用的设计,并且目前我们使用了其中两个属性;
title:这个是定义在Android系统中打开多任务切换窗口时显示的标题
home:是该应用启动时显示的页面,我们传入了一个Scaffold;
翻译过来是脚手架,脚手架的作用就是搭建页面的基本结构;
所以我们给MaterialApp的home属性传入了一个Scaffold对象,作为启动显示的Widget;
appBar是用于设计导航栏的,我们传入了一个title属性;
body是页面的内容部分,我们传入了之前已经创建好的Center中包裹的一个Text的Widget;
在Flutter开发中,我们可以继承自StatelessWidget或者StatefulWidget来创建自己的Widget类;
StatelessWidget: 没有状态改变的Widget,通常这种Widget仅仅是做一些展示工作而已;
StatefulWidget: 需要保存状态,并且可能出现状态改变的Widget;
在上面的案例中对代码的重构,我们使用StatelessWidget即可,所以我们接下来学习一下如果利用StatelessWidget来对我们的代码进行重构;
它们的数据通常是直接写死(放在Widget中的数据,必须被定义为final,为什么呢?我在下一个章节讲解StatefulWidget会讲到);
从parent widget中传入的而且一旦传入就不可以修改;
从InheritedWidget获取来使用的数据
1、让自己创建的Widget继承自StatelessWidget;
2、StatelessWidget包含一个必须重写的方法:build方法;
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return <返回我们的Widget要渲染的Widget,比如一个Text Widget>;
}
}
build方法的解析:
Flutter在拿到我们自己创建的StatelessWidget时,就会执行它的build方法;
我们需要在build方法中告诉Flutter,我们的Widget希望渲染什么元素,比如一个Text Widget;
StatelessWidget没办法主动去执行build方法,当我们使用的数据发生改变时,build方法会被重新执行;
build方法什么情况下被执行呢?:
1、当我们的StatelessWidget第一次被插入到Widget树中时(也就是第一次被创建时);
2、当我们的父Widget(parent widget)发生改变时,子Widget会被重新构建;
3、如果我们的Widget依赖InheritedWidget的一些数据,InheritedWidget数据发生改变时;
1、Flutter整个开发过程中就是形成一个Widget树,所以形成嵌套是很正常的。
2、关于Flutter的代码缩进,更多开发中我们使用的是2个空格(前端开发2个空格居多,你喜欢4个也没问题)
但是,我们开发一个这么简单的程序就出现如此多的嵌套,如果应用程序更复杂呢?
我们可以对我们的代码进行封装,将它们封装到自己的Widget中,创建自己的Widget;
写到这里的时候,发现嵌套太多了,需要对代码重构
import 'package:flutter/material.dart';
main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
home:HYHomePage()
);
}
}
class HYHomePage extends StatelessWidget{
@override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text('第一个flutter程序'),
),
body: HYContentBody(),
);
}
}
class HYContentBody extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Text(
"hello,world",
style: TextStyle(
fontSize: 40,
color: Colors.orange
),
),
);
}
}
import 'package:flutter/material.dart';
main()=>{RunApp()};
class RunApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
home:HYHomePage()
);
}
}
class HYHomePage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('第一个flutter程序'),
),
body: HYContentBody(),
);
}
}
class HYContentBody extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Checkbox(
value: true,
onChanged:(value)=>print("hello,world")),
Text(
"同意协议",
textDirection: TextDirection.ltr,
style: TextStyle(fontSize: 20),
)
],
),
);
}
}
这里已经实现的同意协议了,但是我们发现他是无法动态的,是因为StatelessWidget是没有状态改变的Widget,通常这种Widget仅仅是做一些展示工作而已,接下来使用StatefulWidget改造案例
1.StatefulWidget他的主要作用有两个,一是接收父组件传递过来的数据,二是有State类,可以进行状态管理
2.在改变页面数据的时候要加上setState才可以进行渲染
import 'package:flutter/material.dart';
void main() => runApp(RunApp());
class RunApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home:HYHomePage()
);
}
}
class HYHomePage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('第一个flutter程序'),
),
body: HYContentBody(),
);
}
}
class HYContentBody extends StatefulWidget{
//var falg=true; 错误,所有的widget里面都不能有状态的=>创建一个单独的类,这个类负责维护状态
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return HYContentBodyState();
}
}
class HYContentBodyState extends State<HYContentBody>{
var flag=true;
@override
Widget build(BuildContext context) {
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Checkbox(
value: flag,
onChanged: (value){
setState(() {
flag=value;
});
print(value);
print(flag);
},
),
Text('tongyixieyi',style:TextStyle(fontSize: 20))
],
),
);
}
}
在下面的案例中,很明显一个产品的展示就是一个大的Widget,这个Widget包含如下Widget:
标题的Widget:使用一个Text Widget完成;
描述的Widget:使用一个Text Widget完成;
图片的Widget:使用一个Image Widget完成;
上面三个Widget要垂直排列,我们可以使用一个Column的Widget
另外,三个展示的标题、描述、图片都是不一样的,所以我们可以让Parent Widget来决定内容:
创建三个成员变量保存父Widget传入的数据
import 'package:flutter/material.dart';
void main() => runApp(RunApp());
class RunApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HYHomePage(),
);
}
}
class HYHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text('商品列表'),
),
body: HYHOmeContent(),
);
}
}
class HYHOmeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView( //可滚动区域的widget
children: [
HYHomeProductItem("apple","mac","https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
HYHomeProductItem("apple","mac","https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
HYHomeProductItem("apple","mac","https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
],
);
}
}
class HYHomeProductItem extends StatelessWidget {
final String title;
final String desc;
final String imageURL;
final style01=TextStyle(fontSize: 25,color: Colors.orange);
final style02=TextStyle(fontSize: 20,color: Colors.green);
HYHomeProductItem(this.title,this.desc,this.imageURL);
@override
Widget build(BuildContext context) {
return Container(
padding:EdgeInsets.all(12), //内边距
decoration: BoxDecoration(
border: Border.all( //边框
width: 5,
color: Colors.orange
)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,style: style01,),
SizedBox(height: 8,),//一个盒子 类似于margin
Text(desc,style: style02,),
SizedBox(height: 8,),
Image.network(imageURL),
],
),
);
}
}