前言
在线教程:statelessWidget
参考:Widget 简介
statelessWidget
StatelessWidget用于不需要维护状态的场景,它通常在build方法中通过嵌套其他 widget 来构建UI,在构建过程中会递归的构建其嵌套的 widget 。
基本demo
import 'package:flutter/material.dart';
//使用箭头函数简写
main() => runApp(const MyApp());
// app需要返回一个material类型的app -> MaterialApp需要一个首页,然后创建一个首页的widget(YcHomePage)
// 主页面需要有导航条和内容,借助Scaffold快速创建,然后创建导航条appBar和 body
// body是一个widget,再创建YcHomeBody
class MyApp extends StatelessWidget {
//创建widget的唯一标识
const MyApp({
Key? key}) : super(key: key);
//重写build方法
@override
Widget build(BuildContext context) {
//返回一个material类型的app
return const MaterialApp(
//指定显示哪一个页面
home: YcHomePage(),
);
}
}
//app的主页面
class YcHomePage extends StatelessWidget {
const YcHomePage({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//首页需要有导航和内容,这里借助Scaffold来快速创建
return Scaffold(
//导航条
appBar: AppBar(
title: const Text("商品列表", style: TextStyle(color: Colors.white)),
),
//页面主题内容
body: const YcHomeBody(),
);
}
}
//主页面的body
class YcHomeBody extends StatelessWidget {
const YcHomeBody({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//Column可以在垂直方向排列其子组件
return Column(
children: const [
YcHomeProductItem("vue", "渐进式,JavaScript 框架易学易用,性能出色,适用场景丰富的 Web 前端框架。",
'https://pic3.zhimg.com/v2-d73df22d306f557a0d3d313d78f50f84_1440w.jpg'),
YcHomeProductItem(
"Flutter",
"Flutter 是 Google 推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。",
'https://pic2.zhimg.com/v2-d4475f94d92ae6012a4f2f727a51700d_1440w.jpg'),
YcHomeProductItem(
"Flutter",
"Flutter 是 Google 推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。",
'https://pic2.zhimg.com/v2-d4475f94d92ae6012a4f2f727a51700d_1440w.jpg')
],
);
}
}
//商品
class YcHomeProductItem extends StatelessWidget {
//定义需要的参数,widget里面定义的变量必须是final的
final String title; //标题
final String desc; //描述
final String imgUrl; //图片地址
//构造函数
const YcHomeProductItem(this.title, this.desc, this.imgUrl, {
Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [Text(title), Text(desc), Image.network(imgUrl)],
);
}
}
效果图
这里存在一个问题,当内容超出屏幕的显示范围时会出现下面的这块区域,解决方法就是设置成滚动的区域
优化
将Column
换成 ListView
//主页面的body
class YcHomeBody extends StatelessWidget {
const YcHomeBody({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//Column可以在垂直方向排列其子组件
return ListView(
children: const [
YcHomeProductItem("vue", "渐进式,JavaScript 框架易学易用,性能出色,适用场景丰富的 Web 前端框架。",
'https://pic3.zhimg.com/v2-d73df22d306f557a0d3d313d78f50f84_1440w.jpg'),
YcHomeProductItem(
"Flutter",
"Flutter 是 Google 推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。",
'https://pic2.zhimg.com/v2-d4475f94d92ae6012a4f2f727a51700d_1440w.jpg'),
YcHomeProductItem(
"Flutter",
"Flutter 是 Google 推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。",
'https://pic2.zhimg.com/v2-d4475f94d92ae6012a4f2f727a51700d_1440w.jpg')
],
);
}
}
最终代码
import 'package:flutter/material.dart';
//使用箭头函数简写
main() => runApp(const MyApp());
// app需要返回一个material类型的app -> MaterialApp需要一个首页,然后创建一个首页的widget(YcHomePage)
// 主页面需要有导航条和内容,借助Scaffold快速创建,然后创建导航条appBar和 body
// body是一个widget,再创建YcHomeBody
class MyApp extends StatelessWidget {
//创建widget的唯一标识
const MyApp({
Key? key}) : super(key: key);
//重写build方法
@override
Widget build(BuildContext context) {
//返回一个material类型的app
return const MaterialApp(
//指定显示哪一个页面
home: YcHomePage(),
);
}
}
//app的主页面
class YcHomePage extends StatelessWidget {
const YcHomePage({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//首页需要有导航和内容,这里借助Scaffold来快速创建
return Scaffold(
//导航条
appBar: AppBar(
title: const Text("商品列表", style: TextStyle(color: Colors.white)),
),
//页面主题内容
body: const YcHomeBody(),
);
}
}
//主页面的body
class YcHomeBody extends StatelessWidget {
const YcHomeBody({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//Column可以在垂直方向排列其子组件
return ListView(
children: const [
YcHomeProductItem("vue", "渐进式,JavaScript 框架易学易用,性能出色,适用场景丰富的 Web 前端框架。",
'https://pic3.zhimg.com/v2-d73df22d306f557a0d3d313d78f50f84_1440w.jpg'),
YcHomeProductItem(
"Flutter",
"Flutter 是 Google 推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。",
'https://pic2.zhimg.com/v2-d4475f94d92ae6012a4f2f727a51700d_1440w.jpg'),
YcHomeProductItem(
"Dart",
"Dart是谷歌开发的计算机编程语言,后来被Ecma (ECMA-408)认定为标准。它被用于web、服务器、移动应用和物联网等领域的开发。",
'https://static001.infoq.cn/resource/image/a7/d4/a7db324acf088378d8be46fc42eeaed4.png')
],
);
}
}
//商品
class YcHomeProductItem extends StatelessWidget {
//定义需要的参数,widget里面定义的变量必须是final的
final String title; //标题
final String desc; //描述
final String imgUrl; //图片地址
//构造函数
const YcHomeProductItem(this.title, this.desc, this.imgUrl, {
Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
const titleStyle = TextStyle(fontSize: 24, color: Colors.orange);
const descStyle = TextStyle(fontSize: 16, color: Colors.blue);
return Container(
//内边距
padding: const EdgeInsets.all(8),
//外边距
margin: const EdgeInsets.all(8),
// decoration 装饰,decoration是抽象类,这里使用其子类
decoration: BoxDecoration(
//边框
border: Border.all(
width: 2, //边框的宽度
color: Colors.blueGrey //边框颜色
)),
child: Column(
children: [
Text(title, style: titleStyle),
//使用SizedBox来实现间距,flutter中没有margin
const SizedBox(
height: 8,
),
Text(
desc,
style: descStyle,
),
const SizedBox(
height: 8,
),
Image.network(imgUrl),
const SizedBox(
height: 8,
),
],
),
);
}
}
其他
- Android studio 可以通过
stless
来快速的创建一个statelessWidget - Android studio 将鼠标放在widget,来给widget套一层widget
- widget里面定义的变量必须是final的
- 使用SizedBox来实现间距,flutter中没有margin
- 使用Container来实现边框
StatefulWidget
StatefulWidget 类会对应一个 State 类,State表示与其对应的 StatefulWidget 要维护的状态,State 中的保存的状态信息可以:
- 在 widget 构建时可以被同步读取。
- 在 widget 生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter 框架状态发生改变,Flutter 框架在收到消息后,会重新调用其build方法重新构建 widget 树,从而达到更新UI的目的。
State 中有两个常用属性:
-
widget,它表示与该 State 实例关联的 widget 实例,由Flutter 框架动态设置。注意,这种关联并非永久的,因为在应用生命周期中,UI树上的某一个节点的 widget 实例在重新构建时可能会变化,但State实例只会在第一次插入到树中时被创建,当在重新构建时,如果 widget 被修改了,Flutter 框架会动态设置State. widget 为新的 widget 实例。
-
context。StatefulWidget对应的 BuildContext,作用同StatelessWidget 的BuildContext。
demo
import 'package:flutter/material.dart';
//使用箭头函数简写
main() => runApp(const MyApp());
// app需要返回一个material类型的app -> MaterialApp需要一个首页,然后创建一个首页的widget(YcHomePage)
// 主页面需要有导航条和内容,借助Scaffold快速创建,然后创建导航条appBar和 body
// body是一个widget,再创建YcHomeBody
class MyApp extends StatelessWidget {
//创建widget的唯一标识
const MyApp({
Key? key}) : super(key: key);
//重写build方法
@override
Widget build(BuildContext context) {
//返回一个material类型的app
return const MaterialApp(
//指定显示哪一个页面
home: YcHomePage(),
);
}
}
//app的主页面
class YcHomePage extends StatelessWidget {
const YcHomePage({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//首页需要有导航和内容,这里借助Scaffold来快速创建
return Scaffold(
//导航条
appBar: AppBar(
title: const Text("商品列表", style: TextStyle(color: Colors.white)),
),
//页面主题内容
body: const YcHomeBody("哈哈哈"),
);
}
}
//主页面的body
class YcHomeBody extends StatefulWidget {
// widget是不可变的,必须用final
final String message;
const YcHomeBody(this.message, {
Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
//返回对应的状态类
return _YcHomeBodyState();
}
}
//管理主页body的状态类,状态类前面一般加下划线进行标识
class _YcHomeBodyState extends State<YcHomeBody> {
int _counter = 0;
//可以通过this.widget来获取实例
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_getButton(),
Text("当前计数为:$_counter"),
Text("当前传递的信息是:${widget.message}")
],
));
}
//获取按钮
Widget _getButton() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
setState(() => _counter++);
},
child: const Icon(Icons.add)),
ElevatedButton(
onPressed: () {
setState(() => _counter--);
},
child: const Icon(Icons.remove),
),
],
);
}
}
其他
状态类,前面一般加上_
来进行标识,标识该类是私有的
为什么StatefulWidget的build方法放在State中?
- build出来的widget是需要依赖State中的变量(状态)
widget可以传参,因此参数哈哈哈,只能放在YcHomeBody 里
state源码中有一个变量,我们可以通过该变量拿到widget的实例