Flutter从入门到实战
一共分为23个系列
①(Flutter、Dart环境搭建篇) 共3个内容 已更新
②(Dart语法1 篇) 共4个内容 已更新
③(Dart语法2 篇) 共2个内容 已更新
④(Flutter案例开发篇) 共4个内容 已更新
⑤(Flutter的StatelessWidget 共3个内容 已更新
⑥(Flutter的基础Widget篇) 共2个内容 已更新
⑦(布局Widget篇) 共1个内容 已更新
⑧(Flex、Row、Column以及Flexible、Stack篇) 共1个内容 已更新
⑨(滚动的Widget篇) 共4个内容 已更新
⑩(Dart的Future和网络篇) 共3个内容 已更新
⑪(豆瓣案例-1篇) 共3个内容 已更新
⑫(豆瓣案例-2篇) 共3个内容 已更新
官方文档说明
官方视频教程
Flutter的YouTube视频教程-小部件
⑤、Flutter的StatelessWidget案例-列表展示、StatefulWidget 案例 - 加减操作、 Flutter的Widget生命周期
-
- ①、StatelessWidget 案例 - 列表展示
-
- 1.1 使用`stless`代码智能提示快速创建一个继承于 `StatelessWidget` 的类
- 1.2 简单的Widget树结构 - Hello world 出来了
- 1.2 使用 `Column` Widget 创建列表商品
- 1.2 效果图
- 1.3 将`YHiOSHomeContent` `Column` Widget 改成 `ListView` Widget 效果图 就能解决上面出现的警告区域了
- 1.4 将通过 `TextStyle` 抽取字体大小、颜色 和 通过 `SizedBox` 设置上下的间距
- 1.4 效果图
- 1.5 通过 `alt + enter` 快捷键 进行输出一个`Container` 对象 用来设置内外边距的 边框的大小和颜色
- 1.5 效果图
- 1.6 设置内容 不居中 通过设置交叉轴`crossAxisAlignment`
- 1.6 效果图
- 1.7 通过包裹一个Row 使单个标题居左
- 1.7 效果图
- ②、StatefulWidget 案例 - 加减操作
- ③、Flutter的Widget生命周期
上节课回顾
- Scaffold 小组件
相当于 iOS的ViewController 或者Android的 Activity
看作一个界面- AppBar 相当于 Tabbar
- StatelessWidget 是不能存放变量的 因为是继承 Widget 因为 Widget 使用了 @immutable 这个修饰用来 当前这个类是不可变的 或者子类是不可变的.所有的成员变量必须是 final的
- StatefulWidget 分成2个类
一个是继承 StatefulWidget的类(最主要作用是 必须实现State类,还有一个作用是 可以接受父Widget 传过来的数据),
一个是State类(状态)
①、StatelessWidget 案例 - 列表展示
1.1 使用stless
代码智能提示快速创建一个继承于 StatelessWidget
的类
依次做Widget树结构
App
HomePage
-> 包含 Scaffold
Scaffold
-> 包含 AppBar -> Title
-> 包含 body : HomeContent
HomeContent -> Ttile
1.2 简单的Widget树结构 - Hello world 出来了
import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());
// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类
class MyApp extends StatelessWidget {
const MyApp({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home:YHiOSHomePage() ,
);
}
}
class YHiOSHomePage extends StatelessWidget {
const YHiOSHomePage({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 主页 使用一个小组件 Scaffold
return Scaffold(
appBar: AppBar(
title: Text("商品列表"),
),
body: YHiOSHomeContent(),
);
}
}
class YHiOSHomeContent extends StatelessWidget {
const YHiOSHomeContent({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text("hello world");
}
}
1.2 使用 Column
Widget 创建列表商品
数据都是写死的
该代码的注意细节:
- 抽取列表的每一个item为Widget
- 定义几个变量来记录 item的数据
- 使用Image.network加载网络的图片
import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());
// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类
class MyApp extends StatelessWidget {
const MyApp({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home:YHiOSHomePage() ,
);
}
}
class YHiOSHomePage extends StatelessWidget {
const YHiOSHomePage({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 主页 使用一个小组件 Scaffold
return Scaffold(
appBar: AppBar(
title: Text("商品列表"),
),
body: YHiOSHomeContent(),
);
}
}
class YHiOSHomeContent extends StatelessWidget {
const YHiOSHomeContent({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
YHiOSHomeProductItem("清风衬晚霞1","清风衬晚霞 desc1","https://wx3.sinaimg.cn/mw2000/515a7464ly1h01enjqtdmj20j60j6q3k.jpg"),
YHiOSHomeProductItem("清风衬晚霞2","清风衬晚霞 desc2","https://wx2.sinaimg.cn/orj360/515a7464ly1h01enjqdo4j20j60j6t9b.jpg"),
YHiOSHomeProductItem("清风衬晚霞3","清风衬晚霞 desc3","https://wx2.sinaimg.cn/orj360/515a7464ly1h01enjqx21j20j60j60tc.jpg"),
YHiOSHomeProductItem("清风衬晚霞4","清风衬晚霞 desc3","https://wx2.sinaimg.cn/orj360/515a7464ly1h01enjrqa9j20j60j6q3n.jpg"),
],
);
}
}![请添加图片描述](https://img-blog.csdnimg.cn/8411a711c2a041d0b96e1fd5e78c6844.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a6H5aScaU9T,size_18,color_FFFFFF,t_70,g_se,x_16)
// ⭐️ 抽取商品的item
/**
* 包含 :
* 标题
* 详细
* 图片
* */
// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
final String title ;
final String desc ;
final String imageURL ;
// 构造函数
YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(title),
Text(desc),
Image.network(imageURL)
],
);
}
}
1.2 效果图
我们发现在底部多出了一块警告的区域
relayoutBoundary=up1 OVERFLOWING
布局边界
如何解决
我们需要把Column
Widget 改成ListView
Widget
1.3 将YHiOSHomeContent
Column
Widget 改成 ListView
Widget 效果图 就能解决上面出现的警告区域了
1.4 将通过 TextStyle
抽取字体大小、颜色 和 通过 SizedBox
设置上下的间距
class YHiOSHomeProductItem extends StatelessWidget {
final String title ;
final String desc ;
final String imageURL ;
final style1 = TextStyle(fontSize: 25,color: Colors.orange);
final style2 = TextStyle(fontSize: 20,color: Colors.red);
// 构造函数
YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(title,style: style1),
SizedBox(height: 8),
Text(desc,style: style2),
SizedBox(height: 8),
Image.network(imageURL)
],
);
}
}
1.4 效果图
1.5 通过 alt + enter
快捷键 进行输出一个Container
对象 用来设置内外边距的 边框的大小和颜色
BoxDecoration 设置边框的大小 颜色
padding : EdgeInsets 设置边框的大小
// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
final String title ;
final String desc ;
final String imageURL ;
final style1 = TextStyle(fontSize: 25,color: Colors.orange);
final style2 = TextStyle(fontSize: 20,color: Colors.red);
// 构造函数
YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
@override
Widget build(BuildContext context) {
return Container(
// decoration 装饰
// BoxDecoration 是一个子类
padding: EdgeInsets.all(30),
decoration: BoxDecoration(
border: Border.all(
width: 5, // 设置边框的宽度
color:Colors.purple // 设置边框的颜色
)
),
child: Column(
children: [
Text(title,style: style1),
SizedBox(height: 8),
Text(desc,style: style2),
SizedBox(height: 8),
Image.network(imageURL)
],
),
);
}
}
1.5 效果图
1.6 设置内容 不居中 通过设置交叉轴crossAxisAlignment
Column的垂直方向是主轴 |
Row的水平方向是主轴 –
// ⭐️ 抽取商品的item
/**
* 包含 :
* 标题
* 详细
* 图片
* */
// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
final String title ;
final String desc ;
final String imageURL ;
final style1 = TextStyle(fontSize: 25,color: Colors.orange);
final style2 = TextStyle(fontSize: 20,color: Colors.red);
// 构造函数
YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
@override
Widget build(BuildContext context) {
return Container(
// decoration 装饰
// BoxDecoration 是一个子类
padding: EdgeInsets.all(30),
decoration: BoxDecoration(
border: Border.all(
width: 5, // 设置边框的宽度
color:Colors.purple // 设置边框的颜色
)
),
child: Column(
// 主轴
// mainAxisAlignment: MainAxisAlignment.center,
// 交叉轴
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(title,style: style1),
SizedBox(height: 8),
Text(desc,style: style2),
SizedBox(height: 8),
Image.network(imageURL)
],
),
);
}
}
1.6 效果图
1.7 通过包裹一个Row 使单个标题居左
可以点击指定的Widget 通过 option + enter 包裹一个row
1.7.1 单独设置Text设置居左
Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Text(title,style: style1), ], ),
// ⭐️ 抽取商品的item
/**
* 包含 :
* 标题
* 详细
* 图片
* */
// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
final String title ;
final String desc ;
final String imageURL ;
final style1 = TextStyle(fontSize: 25,color: Colors.orange);
final style2 = TextStyle(fontSize: 20,color: Colors.red);
// 构造函数
YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
@override
Widget build(BuildContext context) {
return Container(
// decoration 装饰
// BoxDecoration 是一个子类
padding: EdgeInsets.all(30),
decoration: BoxDecoration(
border: Border.all(
width: 5, // 设置边框的宽度
color:Colors.purple // 设置边框的颜色
)
),
child: Column(
// 主轴
// mainAxisAlignment: MainAxisAlignment.center,
// 交叉轴
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(title,style: style1),
],
),
SizedBox(height: 8),
Text(desc,style: style2),
SizedBox(height: 8),
Image.network(imageURL)
],
),
);
}
}
1.7 效果图
②、StatefulWidget 案例 - 加减操作
2.1 使用stful
代码智能提示快速创建一个继承于 StatefulWidget
的类
StatefulWidget 中 的 Widget 和 State 注意点
- Widget
StatefulWidget 是一个抽象类
有一个方法是 必须实现的
createState
Widget是不加 _ 因为Wighet是暴露给别人使用的- State
State是加_ : 状态这个是给Widget使用的
Flutter设计StatefulWidget的原理
/** * 为什么Flutter在设计的时候 StatefulWidget 的build方法放在State * 1.build出来的Widget是需要依赖State中的变量(状态/数据) * 2.在Flutter的运行过程中: * Widget是不断地销毁和创建的 * 当我们自己的状态发生改变时,并不希望重新创建一个新的State * */
2.2 使用 Row
嵌套两个 RaisedButton
按钮 用来记录加减号的
// 为什么有些Widget是child 有些是children .最主要是看继承关系. // child 只是包含一个Widget // 有些是children 可以包含多个Widget
当代码嵌套比较多 可以使用抽取方法
比如 两个RaisedButton
// 抽取方法 用于获取按钮
Widget _getButtons() {
return Row(
children: [
RaisedButton(
child: Text("+"),
color: Colors.pink,
onPressed: () => print("点击了+")
),
RaisedButton(
child: Text("-"),
color: Colors.orange,
onPressed: () => print("点击了-")
),
],
);
}
main.dart
import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());
// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类
class MyApp extends StatelessWidget {
const MyApp({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home:YHiOSHomePage() ,
);
}
}
class YHiOSHomePage extends StatelessWidget {
const YHiOSHomePage({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 主页 使用一个小组件 Scaffold
return Scaffold(
appBar: AppBar(
title: Text("商品列表"),
),
body: YHiOSHomeContent(),
);
}
}
// StatefulWidget 是一个抽象类
// 有一个方法是 必须实现的
// createState
// Widget是不加 _ 因为Wighet是暴露给别人使用的
class YHiOSHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _YHiOSHomeContentState();
}
}
// State的代码规范是 以_开头
// State是加_ : 状态这个是给Widget使用的
/**
* 为什么Flutter在设计的时候 StatefulWidget 的build方法放在State
* 1.build出来的Widget是需要依赖State中的变量(状态/数据)
* 2.在Flutter的运行过程中:
* Widget是不断地销毁和创建的
* 当我们自己的状态发生改变时,并不希望重新创建一个新的State
* */
class _YHiOSHomeContentState extends State<YHiOSHomeContent> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Center(
// 为什么有些Widget是child 有些是children .最主要是看继承关系.
// child 只是包含一个Widget
// 有些是children 可以包含多个Widget
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_getButtons(),
Text("当前计数:$_counter",style:TextStyle(fontSize: 30))
],
),
);
}
// 抽取方法 用于获取按钮
Widget _getButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
child: Text("+",style: TextStyle(fontSize: 20,color: Colors.white)),
color: Colors.pink,
onPressed: () {
// 刷新页面 状态更新
setState(() {
_counter++;
});
}
),
RaisedButton(
child: Text("-",style: TextStyle(fontSize: 20,color: Colors.white)),
color: Colors.orange,
onPressed: () {
setState(() {
_counter--;
});
}
),
],
);
}
}
2.2 效果图
③、Flutter的Widget生命周期
3.1 StatelessWidget生命周期
// StatelessWidget的生命周期
class YHiOSHomeContent extends StatelessWidget {
final String message;
YHiOSHomeContent(this.message){
print("构造函数被调用");
}
@override
Widget build(BuildContext context) {
print("调用build方法");
return Text(message);
}
}
⭐️ 3.2 StatefulWidget生命周期
class YHiOSHomeContent extends StatefulWidget {
YHiOSHomeContent(){
print("1.调用了 YHiOSHomeContent 的 constructor方法");
}
@override
_YHiOSHomeContentState createState() {
print("2.调用了 YHiOSHomeContent 的 createState方法");
return _YHiOSHomeContentState();
}
}
class _YHiOSHomeContentState extends State<YHiOSHomeContent> {
_YHiOSHomeContentState() {
print("3.调用了 _YHiOSHomeContentState 的 constructor方法");
}
void initState(){
// 调用: 这里是必须调用 super
//
super.initState();
print("4.调用了 _YHiOSHomeContentState 的 initState方法");
}
@override
Widget build(BuildContext context) {
print("5.调用了 _YHiOSHomeContentState 的 build方法");
return Container();
}
@override
void dispose() {
// TODO: implement dispose
print("6.调用了 _YHiOSHomeContentState 的 dispose方法");
super.dispose();
}
}
3.3 为什么点击的时候 要调用 setState方法进行刷新
因为系统内部已经做了处理 只有调用setState方法之后 .才会重新build
setState方法原理案例 maiin.dart
import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());
// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类
class MyApp extends StatelessWidget {
const MyApp({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home:YHiOSHomePage() ,
);
}
}
class YHiOSHomePage extends StatelessWidget {
const YHiOSHomePage({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 主页 使用一个小组件 Scaffold
return Scaffold(
appBar: AppBar(
title: Text("商品列表"),
),
// body: YHiOSHomeContent("你好呀 宇夜iOS"),
body: YHiOSHomeContent(),
);
}
}
// StatelessWidget的生命周期
// class YHiOSHomeContent extends StatelessWidget {
// final String message;
//
// YHiOSHomeContent(this.message){
// print("构造函数被调用");
// }
// @override
// Widget build(BuildContext context) {
// print("调用build方法");
// return Text(message);
// }
// }
// StatefulWidget的生命周期
//
class YHiOSHomeContent extends StatefulWidget {
YHiOSHomeContent(){
print("1.调用了 YHiOSHomeContent 的 constructor方法");
}
@override
_YHiOSHomeContentState createState() {
print("2.调用了 YHiOSHomeContent 的 createState方法");
return _YHiOSHomeContentState();
}
}
class _YHiOSHomeContentState extends State<YHiOSHomeContent> {
int _counter = 0;
_YHiOSHomeContentState() {
print("3.调用了 _YHiOSHomeContentState 的 constructor方法");
}
void initState(){
// 调用: 这里是必须调用 super
//
super.initState();
print("4.调用了 _YHiOSHomeContentState 的 initState方法");
}
@override
Widget build(BuildContext context) {
print("5.调用了 _YHiOSHomeContentState 的 build方法");
return Column(
children: [
RaisedButton(
child: Icon(Icons.add),
onPressed: (){
setState(() {
_counter ++;
});
},
),
Text("数字:$_counter")
],
);
}
@override
void dispose() {
// TODO: implement dispose
print("6.调用了 _YHiOSHomeContentState 的 dispose方法");
super.dispose();
}
}