flutter create projectname
即可,创建完成使用自己喜欢的工具打开项目即可Android Studio
进行创建,选择Start a new Flutter project
之后,填写相关信息即可在目录下有一个lib
文件夹,里面会存放我们编写的Flutter代码;
打开发现里面有一个main.dart
,它是我们Flutter
启动的入口文件,里面有main
函数;
我们第一次接触main.dart中的代码,可能会发现很多不认识的代码,作为初学者,我的建议是将其中所有的代码全部删除掉,从零去创建里面的代码,这样我们才能对Flutter应用程序的结构非常清晰;
快捷调试按钮:
需求:在界面中心位置,显示一个Hello World
import 'package:flutter/material.dart';//导入对应的库
//main函数作为程序的入口
void main() {
runApp(
Text(
"hello world",
textDirection: TextDirection.ltr,//设置文字的显示方向, 如果不设置方向会报错
style: TextStyle(
fontSize: 30
),
)
);
}
Dart程序的入口都是main函数
,而Flutter是Dart编写的,所以入口也是main函数Material是什么呢?
runApp()函数
又是什么呢?runApp
是Flutter
内部提供的一个函数,当我们启动一个Flutter应用程序时就是从调用这个函数开始的
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
Widget
,那么什么是Widget
?
Flutter中万物皆Widget
但是在Flutter中,这些东西都是不同的Widget而已
所看到的内容几乎都是Widget
,甚至是内边距的设置,我们也需要使用一个叫Padding的Widget
来做runApp
函数让我们传入的就是一个Widget
:我们可以导入Flutter默认已经给我们提供的Material
库,来使用其中的很多内置Widget;material
是什么呢?
material
是Google公司推行的一套设计风格
,或者叫设计语言
、设计规范
等;颜色、文字的排版、响应动画与过度、填充
等等;Material风格的Widget
;Text小部件分析:
StatelessWidget
,StatelessWidget
继承自Widget
;class Text extends StatelessWidget {
const Text(
this.data, { //data 为必传参数 其它都是命名可选参数
Key key,
this.style,
this.strutStyle,
this.textAlign,
this.textDirection,
this.locale,
this.softWrap,
this.overflow,
this.textScaleFactor,
this.maxLines,
this.semanticsLabel,
this.textWidthBasis,
});
}
abstract class StatelessWidget extends Widget {
// ...省略代码
}
Center
;import 'package:flutter/material.dart';//导入对应的库
//main函数作为程序的入口
void main() {
runApp(
Center( // 居中小部件
child: Text(
"hello world",
textDirection: TextDirection.ltr,//设置文字的显示方式
style: TextStyle(
fontSize: 30 //设置字体大小
),
),
)
);
}
目前我们虽然可以显示HelloWorld,但是我们发现最底部的背景是黑色,并且我们的页面并不够结构化。 正常的App页面应该有一定的结构,比如通常都会有导航栏
,会有一些背景颜色
等
在flutter开发当中
,我们并不需要从零去搭建这种结构化的界面,我们可以使用Material库,直接使用其中的一些封装好的组件来完成一些结构的搭建。
我们通过下面代码来实现:
import 'package:flutter/material.dart';//导入对应的库
//main函数作为程序的入口
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
"Hello Flutter"
),
),
body: Center(
child: Text(
"hello world",
textDirection: TextDirection.ltr,//设置文字的显示方式
style: TextStyle(
fontSize: 30 //设置字体大小
),
),
),
)
)
);
}
MaterialApp
title
:这个是定义在Android系统中打开多任务切换窗口时显示的标题;(暂时可以不写)Scaffold
是什么呢?
脚手架
,脚手架的作用就是搭建页面的基本结构;Scaffold
也有一些属性,比如appBar
和body
;appBar
是用于设计导航栏的,我们传入了一个title
属性body
是页面的内容部分,我们传入了之前已经创建好的Center中包裹的一个Text的Widget我们可以让界面中展示更多的界面元素
import 'package:flutter/material.dart';//导入对应的库
//main函数作为程序的入口
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
"Hello Flutter"
),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,//设置主轴居中
children: [
Checkbox(value: true,
onChanged: (value){
print("checkbox 点击事件");
}),
Text(
"同意协议",
textDirection: TextDirection.ltr,//设置文字的显示方式
style: TextStyle(
fontSize: 30 //设置字体大小
),
),
],
)
),
)
)
);
}
我们可以发现上面的代码嵌套已经很多,很多学习Flutter的人,都会被Flutter的嵌套
劝退,当代码嵌套过多时,结构很容易看不清晰。
StatelessWidget
或者StatefulWidget
来创建自己的Widget类;StatelessWidget
: 没有状态改变的Widget,通常这种Widget仅仅是做一些展示工作而已;StatefulWidget
: 需要保存状态,并且可能出现状态改变的Widget;在上述案例中对代码的重构我们使用StatelessWidget
即可
StatelessWidget通常是一些没有状态(State,也可以理解成data)需要维护的Widget
创建自己的Widget
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return <返回我们的Widget要渲染的Widget,比如一个Text Widget>;
}
}
我们可以通过StatelessWidget
对我们的代码进行重构
import 'package:flutter/material.dart';//导入对应的库
//main函数作为程序的入口
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
"Hello Flutter"
),
),
body: GYHomeContent()
)
);
}
}
class GYHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,//设置主轴居中
children: [
Checkbox(value: true,
onChanged: (value){
print("checkbox 点击事件");
}),
Text(
"同意协议",
textDirection: TextDirection.ltr,//设置文字的显示方式
style: TextStyle(
fontSize: 30 //设置字体大小
),
),
],
)
);
}
}
有得人可能想这样实现(错误代码
):
class GYHomeContent extends StatelessWidget {
var flag = true;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,//设置主轴居中
children: [
Checkbox(value: flag,
onChanged: (value){
flag = value; //报错
print("checkbox 点击事件 $value");
}),
Text(
"同意协议",
textDirection: TextDirection.ltr,//设置文字的显示方式
style: TextStyle(
fontSize: 30 //设置字体大小
),
),
],
)
);
}
}
上述代码定义一个变量是错误的写法, 我们可以看到该类的父类是 使用 @inmutable 这个注解标注过, 表示这个类是不可变的, 该注解主要的作用是,修改的当前的类是不可变的 ,一旦创建完成里面所有的东西都是不可变的,里面定义的所有的东西, 属性都是final的,所以里面定义的属性都必须使用final来修饰
所有的Widget里面都是不可以写状态代码的,因为@inmutable修饰的Widget,所以所有的Widget都是不可变的
import 'package:flutter/material.dart';//导入对应的库
//main函数作为程序的入口
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
"Hello Flutter"
),
),
body: GYHomeContent()
)
);
}
}
class GYHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return GYHomeContentBody();
}
}
// StatefullWidget: 继承自StatefulWidget的类(可以接收父Widget传过来的数据)/State类(状态)
// flag: 状态
// Stateful不能定义状态 -> 创建一个单独的类, 这个类负责维护状态
class GYHomeContentBody extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return GYHomeContentBodyState();
}
}
class GYHomeContentBodyState extends State<GYHomeContentBody> {
var flag = true;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,//设置主轴居中
children: [
Checkbox(value: flag,
onChanged: (value){
setState(() {
flag = value ?? true; //因为value是bool? 类型所以需要处理下
});
print("checkbox 点击事件 $flag");
}),
Text(
"同意协议", style: TextStyle(
fontSize: 30 //设置字体大小
),
),
],
)
);
}
}
运行打印效果:
这个案例中可能有用到了一些我们不熟悉的Widget,该案例的主要目的还是让我们更加熟悉Flutter的开发模式以及自定义Widget的封装过程;
//定义一个Item
class GYProductItem extends StatelessWidget {
final String title;
final String desc;
final String imageURL;
//定义一个初始化方法
GYProductItem(this.title, this.desc, this.imageURL);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: [
Text(title, style: TextStyle(fontSize: 24)),
Text(desc, style: TextStyle(fontSize: 18)),
Image.network(imageURL)
],
);
}
class GYHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: [
GYProductItem("Apple1", "Macbook Product1", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
GYProductItem("Apple2", "Macbook Product2", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imm9u5zj30u00k0adf.jpg"),
GYProductItem("Apple3", "Macbook Product3", "https://tva1.sinaimg.cn/large/006y8mN6gy1g72imqlouhj30u00k00v0.jpg")
],
);
}
}
最终实现代码:
import 'package:flutter/material.dart';//导入对应的库
//main函数作为程序的入口
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
"Hello Flutter"
),
),
body: GYHomeContent()
)
);
}
}
class GYHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
GYProductItem("Apple1", "Macbook Product1",
"https://tva1.sinaimg.cn/large/006y8mN6gy1g72j6nk1d4j30u00k0n0j.jpg"),
GYProductItem("Apple2", "Macbook Product2",
"https://tva1.sinaimg.cn/large/006y8mN6gy1g72imm9u5zj30u00k0adf.jpg"),
GYProductItem("Apple3", "Macbook Product3",
"https://tva1.sinaimg.cn/large/006y8mN6gy1g72imqlouhj30u00k00v0.jpg")
],
),
);
}
}
//定义一个Item
class GYProductItem extends StatelessWidget {
final String title;
final String desc;
final String imageURL;
//定义一个初始化方法
GYProductItem(this.title, this.desc, this.imageURL);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
border: Border.all()
),
child: Column(
children: [
Text(title, style: TextStyle(fontSize: 24)),
Text(desc, style: TextStyle(fontSize: 18)),
Image.network(imageURL)
],
),
);
}
}