Hello Flutter:Text, Image, Icon 基础组件全攻略,积木式搭建你的第一个页面
·

2.1 Text Widget - 就像写字板
Text Widget就像现实中的各种文字载体:标语牌、书本、标签等。
🔍 Text Widget的内部实现原理
想象Text Widget就像一个智能的文字工厂,让我们看看它是如何从基础Widget一步步构建出来的:
// 🏗️ Text Widget的简化实现原理(教学版本)
// 第一层:最基础的Widget抽象类
abstract class Widget {
// 每个Widget都有一个key来标识自己
final Key? key;
Widget({this.key});
// 核心方法:创建Element
Element createElement();
}
// 第二层:StatelessWidget基类
abstract class StatelessWidget extends Widget {
StatelessWidget({Key? key}) : super(key: key);
StatelessElement createElement() => StatelessElement(this);
// 子类必须实现的方法
Widget build(BuildContext context);
}
// 第三层:Text Widget的实际实现
class MyText extends StatelessWidget {
final String data; // 要显示的文字
final TextStyle? style; // 文字样式
final TextAlign? textAlign; // 文字对齐方式
final int? maxLines; // 最大行数
final TextOverflow? overflow; // 溢出处理
const MyText(
this.data, {
Key? key,
this.style,
this.textAlign,
this.maxLines,
this.overflow,
}) : super(key: key);
Widget build(BuildContext context) {
// 🎨 这里是Text Widget的核心逻辑
// 1. 获取主题中的默认文字样式
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
TextStyle? effectiveTextStyle = style;
if (style == null || style!.inherit) {
effectiveTextStyle = defaultTextStyle.style.merge(style);
}
// 2. 创建RichText Widget(Text的底层实现)
return RichText(
textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start,
maxLines: maxLines ?? defaultTextStyle.maxLines,
overflow: overflow ?? defaultTextStyle.overflow,
text: TextSpan(
text: data,
style: effectiveTextStyle,
),
);
}
}
// 🎭 生活类比:Text Widget就像一个文字印刷厂
/*
想象Text Widget的工作流程:
1. 原材料输入(构造函数)
- 文字内容 (data)
- 样式要求 (style)
- 排版要求 (textAlign, maxLines等)
2. 工厂处理(build方法)
- 检查主题设置(就像印刷厂的标准模板)
- 合并样式(就像选择字体、颜色、大小)
- 创建最终产品(RichText)
3. 产品输出
- 在屏幕上显示格式化的文字
*/
// 🔧 Text Widget的核心组件分析
// TextSpan - 文字片段(就像一个个文字积木)
class TextSpanExample extends StatelessWidget {
Widget build(BuildContext context) {
return RichText(
text: TextSpan(
text: '这是普通文字,',
style: TextStyle(color: Colors.black, fontSize: 16),
children: [
TextSpan(
text: '这是粗体文字,',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(
text: '这是彩色文字!',
style: TextStyle(color: Colors.red),
),
],
),
);
}
}
// TextStyle - 文字样式(就像文字的化妆师)
class TextStyleExample extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
Text(
'样式演示',
style: TextStyle(
fontSize: 24, // 字体大小(就像放大镜的倍数)
fontWeight: FontWeight.bold, // 字体粗细(就像笔的粗细)
color: Colors.blue, // 颜色(就像墨水的颜色)
letterSpacing: 2.0, // 字母间距(就像字与字的距离)
wordSpacing: 4.0, // 单词间距
height: 1.5, // 行高(就像行与行的距离)
decoration: TextDecoration.underline, // 装饰(下划线)
decorationColor: Colors.red, // 装饰颜色
decorationStyle: TextDecorationStyle.wavy, // 装饰样式(波浪线)
shadows: [ // 阴影效果
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 3.0,
color: Colors.grey,
),
],
),
),
],
);
}
}
// 🎯 Text Widget的渲染流程
/*
Text Widget的渲染就像一个文字处理流水线:
1. 输入阶段:
- 接收文字内容和样式参数
- 就像印刷厂接收订单
2. 处理阶段:
- 解析文字内容
- 应用样式设置
- 计算布局信息
- 就像排版师设计版面
3. 渲染阶段:
- 在Canvas上绘制文字
- 应用颜色、阴影等效果
- 就像印刷机印刷成品
4. 显示阶段:
- 在屏幕上显示最终结果
- 就像成品展示
*/
// 🧪 自定义Text Widget示例
class CustomText extends StatelessWidget {
final String text;
final Color? color;
final double? fontSize;
final bool isBold;
const CustomText(
this.text, {
Key? key,
this.color,
this.fontSize,
this.isBold = false,
}) : super(key: key);
Widget build(BuildContext context) {
return Text(
text,
style: TextStyle(
color: color ?? Colors.black,
fontSize: fontSize ?? 16,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
),
);
}
}
class TextExamples extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('文字展示大全')),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 普通文字 - 就像普通的标签
Text('这是普通文字'),
SizedBox(height: 16),
// 大标题 - 就像海报上的主标题
Text(
'这是大标题',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
SizedBox(height: 16),
// 彩色文字 - 就像用彩色笔写的字
Text(
'这是彩色文字',
style: TextStyle(
fontSize: 18,
color: Colors.red,
fontStyle: FontStyle.italic, // 斜体
),
),
SizedBox(height: 16),
// 多行文字 - 就像一段文章
Text(
'这是一段很长的文字,用来演示文字换行的效果。'
'当文字太长时,会自动换到下一行显示。'
'就像我们平时看书一样。',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 16),
// 限制行数的文字 - 就像报纸的标题栏
Text(
'这是一段超级超级超级长的文字,但是我们只显示一行,多余的用省略号表示',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
],
),
),
);
}
}
2.2 Image Widget - 就像相框
Image Widget就像现实中的各种图片展示方式:相框、海报、屏幕等。
🔍 Image Widget的内部实现原理
想象Image Widget就像一个智能的图片处理工厂,让我们看看它是如何从基础Widget构建出来的:
// 🏗️ Image Widget的简化实现原理(教学版本)
// Image Widget的核心实现
class MyImage extends StatefulWidget {
final ImageProvider image; // 图片提供者(数据源)
final double? width; // 宽度
final double? height; // 高度
final BoxFit? fit; // 适应方式
final Color? color; // 颜色滤镜
final BlendMode? colorBlendMode; // 混合模式
const MyImage({
Key? key,
required this.image,
this.width,
this.height,
this.fit,
this.color,
this.colorBlendMode,
}) : super(key: key);
_MyImageState createState() => _MyImageState();
}
class _MyImageState extends State<MyImage> {
ImageStream? _imageStream;
ImageInfo? _imageInfo;
bool _isLoading = true;
void initState() {
super.initState();
_loadImage();
}
void _loadImage() {
// 🎯 图片加载流程
// 1. 从ImageProvider获取ImageStream
_imageStream = widget.image.resolve(ImageConfiguration.empty);
// 2. 监听图片加载完成
_imageStream!.addListener(ImageStreamListener(
(ImageInfo info, bool synchronousCall) {
setState(() {
_imageInfo = info;
_isLoading = false;
});
},
onError: (dynamic error, StackTrace? stackTrace) {
setState(() {
_isLoading = false;
});
},
));
}
Widget build(BuildContext context) {
if (_isLoading) {
// 加载中显示占位符
return Container(
width: widget.width,
height: widget.height,
color: Colors.grey[300],
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (_imageInfo == null) {
// 加载失败显示错误
return Container(
width: widget.width,
height: widget.height,
color: Colors.grey[300],
child: Center(
child: Icon(Icons.error),
),
);
}
// 🎨 使用RawImage渲染图片(Image的底层实现)
return RawImage(
image: _imageInfo!.image,
width: widget.width,
height: widget.height,
fit: widget.fit ?? BoxFit.scaleDown,
color: widget.color,
colorBlendMode: widget.colorBlendMode,
);
}
void dispose() {
_imageStream?.removeListener(ImageStreamListener((info, sync) {}));
super.dispose();
}
}
// 🎭 生活类比:Image Widget就像一个智能相框工厂
/*
想象Image Widget的工作流程:
1. 订单接收(构造函数)
- 图片来源 (ImageProvider)
- 尺寸要求 (width, height)
- 显示方式 (fit)
- 特效要求 (color, colorBlendMode)
2. 图片获取(resolve阶段)
- 网络图片:从网络下载
- 本地图片:从文件系统读取
- 资源图片:从应用包中提取
- 就像相框工厂从不同渠道获取照片
3. 图片处理(加载阶段)
- 解码图片数据
- 缓存处理
- 尺寸调整
- 就像照片冲洗和裁剪
4. 显示渲染(build阶段)
- 应用适应方式
- 添加颜色滤镜
- 在屏幕上绘制
- 就像把照片装进相框展示
*/
// 🔧 ImageProvider 系列 - 图片数据源
// 网络图片提供者
class NetworkImageExample extends StatelessWidget {
Widget build(BuildContext context) {
return Image(
image: NetworkImage('https://picsum.photos/300/200'),
// 等价于:Image.network('https://picsum.photos/300/200')
);
}
}
// 资源图片提供者
class AssetImageExample extends StatelessWidget {
Widget build(BuildContext context) {
return Image(
image: AssetImage('assets/images/logo.png'),
// 等价于:Image.asset('assets/images/logo.png')
);
}
}
// 文件图片提供者
class FileImageExample extends StatelessWidget {
Widget build(BuildContext context) {
return Image(
image: FileImage(File('/path/to/image.jpg')),
// 等价于:Image.file(File('/path/to/image.jpg'))
);
}
}
// 内存图片提供者
class MemoryImageExample extends StatelessWidget {
Widget build(BuildContext context) {
// 假设bytes是图片的字节数据
Uint8List bytes = Uint8List(0);
return Image(
image: MemoryImage(bytes),
// 等价于:Image.memory(bytes)
);
}
}
// 🎯 BoxFit 适应方式详解
class BoxFitExample extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
Text('不同的BoxFit效果:'),
SizedBox(height: 16),
// 创建一个网格来展示不同的fit效果
GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
children: [
_buildFitExample(BoxFit.fill, 'fill - 填满容器'),
_buildFitExample(BoxFit.contain, 'contain - 完整显示'),
_buildFitExample(BoxFit.cover, 'cover - 覆盖容器'),
_buildFitExample(BoxFit.fitWidth, 'fitWidth - 适应宽度'),
_buildFitExample(BoxFit.fitHeight, 'fitHeight - 适应高度'),
_buildFitExample(BoxFit.scaleDown, 'scaleDown - 缩小显示'),
],
),
],
);
}
Widget _buildFitExample(BoxFit fit, String description) {
return Column(
children: [
Container(
width: 120,
height: 80,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
),
child: Image.network(
'https://picsum.photos/200/300', // 高宽比不同的图片
fit: fit,
),
),
SizedBox(height: 4),
Text(description, style: TextStyle(fontSize: 10)),
],
);
}
}
// 🎨 图片处理和特效
class ImageEffectsExample extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
Text('图片特效演示:'),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
// 原图
Column(
children: [
Container(
width: 80,
height: 80,
child: Image.network('https://picsum.photos/100/100'),
),
Text('原图'),
],
),
// 颜色滤镜
Column(
children: [
Container(
width: 80,
height: 80,
child: Image.network(
'https://picsum.photos/100/100',
color: Colors.red.withOpacity(0.5),
colorBlendMode: BlendMode.multiply,
),
),
Text('红色滤镜'),
],
),
// 灰度效果
Column(
children: [
Container(
width: 80,
height: 80,
child: ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.grey,
BlendMode.saturation,
),
child: Image.network('https://picsum.photos/100/100'),
),
),
Text('灰度效果'),
],
),
],
),
],
);
}
}
// 🔄 图片缓存机制
/*
Image Widget的缓存就像一个智能的照片管理系统:
1. 内存缓存(Memory Cache)
- 就像桌面上的常用照片
- 访问最快,但容量有限
- 应用关闭后消失
2. 磁盘缓存(Disk Cache)
- 就像相册里的照片
- 访问较快,容量较大
- 应用关闭后仍然存在
3. 缓存策略
- LRU(最近最少使用)淘汰
- 就像整理相册,把不常看的照片收起来
4. 缓存控制
- 可以清除缓存
- 可以预加载图片
- 可以设置缓存大小
*/
// 自定义图片缓存示例
class CustomImageCache extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
// 清除图片缓存
PaintingBinding.instance.imageCache.clear();
print('图片缓存已清除');
},
child: Text('清除图片缓存'),
),
ElevatedButton(
onPressed: () {
// 预加载图片
precacheImage(
NetworkImage('https://picsum.photos/400/300'),
context,
);
print('图片预加载完成');
},
child: Text('预加载图片'),
),
Text('当前缓存信息:'),
Text('缓存图片数量: ${PaintingBinding.instance.imageCache.currentSize}'),
Text('缓存大小限制: ${PaintingBinding.instance.imageCache.maximumSize}'),
],
);
}
}
// 🧪 自定义Image Widget示例
class CustomImageWidget extends StatelessWidget {
final String imageUrl;
final double? width;
final double? height;
final Widget? placeholder;
final Widget? errorWidget;
const CustomImageWidget({
Key? key,
required this.imageUrl,
this.width,
this.height,
this.placeholder,
this.errorWidget,
}) : super(key: key);
Widget build(BuildContext context) {
return Container(
width: width,
height: height,
child: Image.network(
imageUrl,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return placeholder ?? Container(
color: Colors.grey[300],
child: Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return errorWidget ?? Container(
color: Colors.grey[300],
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error, color: Colors.red),
Text('加载失败', style: TextStyle(color: Colors.red)),
],
),
),
);
},
),
);
}
}
class ImageExamples extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('图片展示大全')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
// 网络图片 - 就像从互联网下载的照片
Container(
height: 200,
width: double.infinity,
child: Image.network(
'https://picsum.photos/400/200',
fit: BoxFit.cover, // 就像把照片裁剪适合相框
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(), // 加载中的转圈圈
);
},
errorBuilder: (context, error, stackTrace) {
return Container(
color: Colors.grey[300],
child: Center(
child: Text('图片加载失败'),
),
);
},
),
),
SizedBox(height: 20),
// 本地资源图片 - 就像相册里的照片
// 注意:需要在pubspec.yaml中添加assets配置
Container(
height: 150,
child: Image.asset(
'assets/images/flutter_logo.png',
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return Container(
color: Colors.blue[100],
child: Center(
child: Icon(Icons.image, size: 50),
),
);
},
),
),
SizedBox(height: 20),
// 圆形头像 - 就像证件照
CircleAvatar(
radius: 50,
backgroundImage: NetworkImage('https://picsum.photos/100/100'),
child: Text('头像'), // 当图片加载失败时显示
),
SizedBox(height: 20),
// 不同的图片适应方式
Text('不同的图片适应方式:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 10),
Row(
children: [
Expanded(
child: Column(
children: [
Container(
height: 100,
color: Colors.grey[300],
child: Image.network(
'https://picsum.photos/200/300',
fit: BoxFit.cover, // 覆盖整个容器
),
),
Text('cover - 覆盖'),
],
),
),
SizedBox(width: 10),
Expanded(
child: Column(
children: [
Container(
height: 100,
color: Colors.grey[300],
child: Image.network(
'https://picsum.photos/200/300',
fit: BoxFit.contain, // 完整显示
),
),
Text('contain - 完整显示'),
],
),
),
],
),
],
),
),
);
}
}
2.3 Icon Widget - 就像标识符号
Icon Widget就像现实中的各种符号:交通标志、商店标识、按钮图标等。
class IconExamples extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('图标展示大全')),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
// 基础图标展示
Text('基础图标:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Icon(Icons.home, size: 40, color: Colors.blue),
Text('首页'),
],
),
Column(
children: [
Icon(Icons.favorite, size: 40, color: Colors.red),
Text('喜欢'),
],
),
Column(
children: [
Icon(Icons.settings, size: 40, color: Colors.grey),
Text('设置'),
],
),
Column(
children: [
Icon(Icons.person, size: 40, color: Colors.green),
Text('个人'),
],
),
],
),
SizedBox(height: 32),
// 不同大小的图标
Text('不同大小的图标:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Icon(Icons.star, size: 20, color: Colors.orange),
Icon(Icons.star, size: 30, color: Colors.orange),
Icon(Icons.star, size: 40, color: Colors.orange),
Icon(Icons.star, size: 50, color: Colors.orange),
],
),
SizedBox(height: 32),
// 带背景的图标
Text('带背景的图标:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
// 圆形背景
Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
child: Icon(Icons.phone, color: Colors.white),
),
// 方形背景
Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(8),
),
child: Icon(Icons.message, color: Colors.white),
),
// 带边框的背景
Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: Colors.red, width: 2),
borderRadius: BorderRadius.circular(8),
),
child: Icon(Icons.email, color: Colors.red),
),
],
),
SizedBox(height: 32),
// 常用图标集合
Text('常用图标集合:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Wrap(
spacing: 20,
runSpacing: 20,
children: [
_buildIconWithLabel(Icons.add, '添加'),
_buildIconWithLabel(Icons.delete, '删除'),
_buildIconWithLabel(Icons.edit, '编辑'),
_buildIconWithLabel(Icons.search, '搜索'),
_buildIconWithLabel(Icons.share, '分享'),
_buildIconWithLabel(Icons.download, '下载'),
_buildIconWithLabel(Icons.upload, '上传'),
_buildIconWithLabel(Icons.refresh, '刷新'),
],
),
],
),
),
);
}
Widget _buildIconWithLabel(IconData icon, String label) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 30, color: Colors.blue[700]),
SizedBox(height: 4),
Text(label, style: TextStyle(fontSize: 12)),
],
);
}
}
2.4 Container Widget - 就像万能盒子
Container就像现实中的各种容器:盒子、相框、房间等,可以装饰和包装其他物品。
class ContainerExamples extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('容器展示大全')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
// 基础容器 - 就像一个简单的盒子
Text('基础容器:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
width: 200,
height: 100,
color: Colors.blue[100],
child: Center(
child: Text('我是一个简单的盒子'),
),
),
SizedBox(height: 32),
// 带装饰的容器 - 就像装饰过的礼品盒
Text('装饰容器:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
width: 200,
height: 100,
decoration: BoxDecoration(
color: Colors.pink[100],
border: Border.all(color: Colors.pink, width: 2),
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Center(
child: Text('我是装饰过的盒子'),
),
),
SizedBox(height: 32),
// 带内边距的容器 - 就像盒子里的缓冲材料
Text('带内边距的容器:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
width: 200,
height: 120,
color: Colors.green[100],
padding: EdgeInsets.all(20), // 内边距
child: Container(
color: Colors.green[300],
child: Center(
child: Text('内容'),
),
),
),
SizedBox(height: 32),
// 带外边距的容器 - 就像盒子周围的空间
Text('带外边距的容器:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
color: Colors.grey[200],
child: Container(
width: 150,
height: 80,
margin: EdgeInsets.all(20), // 外边距
color: Colors.orange[200],
child: Center(
child: Text('我有外边距'),
),
),
),
SizedBox(height: 32),
// 不同形状的容器
Text('不同形状的容器:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
// 圆形容器
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.red[200],
shape: BoxShape.circle,
),
child: Center(child: Text('圆形')),
),
// 圆角矩形容器
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.blue[200],
borderRadius: BorderRadius.circular(20),
),
child: Center(child: Text('圆角')),
),
// 椭圆形容器
Container(
width: 100,
height: 60,
decoration: BoxDecoration(
color: Colors.purple[200],
borderRadius: BorderRadius.circular(30),
),
child: Center(child: Text('椭圆')),
),
],
),
SizedBox(height: 32),
// 渐变背景容器 - 就像彩虹色的盒子
Text('渐变背景容器:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
width: 200,
height: 100,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.purple],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: Text(
'渐变背景',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
),
),
],
),
),
);
}
}
2.5 Button系列组件 - 就像各种开关和按钮
按钮就像现实中的各种开关、按键:电灯开关、电梯按钮、遥控器按键等。
class ButtonExamples extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('按钮展示大全')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// ElevatedButton - 就像立体的按钮
Text('立体按钮 (ElevatedButton):', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
_showMessage(context, '你点击了立体按钮!');
},
child: Text('点击我'),
),
SizedBox(height: 16),
// 自定义样式的立体按钮
ElevatedButton(
onPressed: () {
_showMessage(context, '你点击了自定义按钮!');
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: Text('自定义样式按钮'),
),
SizedBox(height: 32),
// TextButton - 就像文字链接
Text('文字按钮 (TextButton):', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
TextButton(
onPressed: () {
_showMessage(context, '你点击了文字按钮!');
},
child: Text('我是文字按钮'),
),
TextButton(
onPressed: () {
_showMessage(context, '你点击了彩色文字按钮!');
},
style: TextButton.styleFrom(
foregroundColor: Colors.purple,
textStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
child: Text('彩色文字按钮'),
),
SizedBox(height: 32),
// OutlinedButton - 就像有边框的按钮
Text('边框按钮 (OutlinedButton):', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
OutlinedButton(
onPressed: () {
_showMessage(context, '你点击了边框按钮!');
},
child: Text('边框按钮'),
),
OutlinedButton(
onPressed: () {
_showMessage(context, '你点击了自定义边框按钮!');
},
style: OutlinedButton.styleFrom(
foregroundColor: Colors.green,
side: BorderSide(color: Colors.green, width: 2),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
child: Text('自定义边框按钮'),
),
SizedBox(height: 32),
// IconButton - 就像只有图标的按钮
Text('图标按钮 (IconButton):', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
onPressed: () {
_showMessage(context, '你点击了喜欢按钮!');
},
icon: Icon(Icons.favorite),
color: Colors.red,
iconSize: 30,
),
IconButton(
onPressed: () {
_showMessage(context, '你点击了分享按钮!');
},
icon: Icon(Icons.share),
color: Colors.blue,
iconSize: 30,
),
IconButton(
onPressed: () {
_showMessage(context, '你点击了设置按钮!');
},
icon: Icon(Icons.settings),
color: Colors.grey,
iconSize: 30,
),
],
),
SizedBox(height: 32),
// FloatingActionButton - 就像悬浮的圆形按钮
Text('悬浮按钮 (FloatingActionButton):', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Center(
child: FloatingActionButton(
onPressed: () {
_showMessage(context, '你点击了悬浮按钮!');
},
child: Icon(Icons.add),
backgroundColor: Colors.blue,
),
),
SizedBox(height: 16),
// 扩展的悬浮按钮
Center(
child: FloatingActionButton.extended(
onPressed: () {
_showMessage(context, '你点击了扩展悬浮按钮!');
},
icon: Icon(Icons.edit),
label: Text('编辑'),
backgroundColor: Colors.green,
),
),
SizedBox(height: 32),
// 带图标的按钮
Text('带图标的按钮:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
ElevatedButton.icon(
onPressed: () {
_showMessage(context, '你点击了下载按钮!');
},
icon: Icon(Icons.download),
label: Text('下载'),
),
SizedBox(height: 16),
OutlinedButton.icon(
onPressed: () {
_showMessage(context, '你点击了上传按钮!');
},
icon: Icon(Icons.upload),
label: Text('上传'),
),
SizedBox(height: 32),
// 禁用状态的按钮
Text('禁用状态的按钮:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
ElevatedButton(
onPressed: null, // null表示禁用
child: Text('禁用的按钮'),
),
SizedBox(height: 16),
OutlinedButton(
onPressed: null,
child: Text('禁用的边框按钮'),
),
],
),
),
);
}
void _showMessage(BuildContext context, String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: Duration(seconds: 2),
),
);
}
}
🎯 实践练习
练习1:创建个人名片应用
class PersonalCardApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: '个人名片',
home: PersonalCard(),
);
}
}
class PersonalCard extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue[50],
appBar: AppBar(
title: Text('我的名片'),
backgroundColor: Colors.blue[600],
elevation: 0,
),
body: Center(
child: Container(
margin: EdgeInsets.all(20),
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 2,
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 头像
CircleAvatar(
radius: 50,
backgroundColor: Colors.blue[200],
child: Icon(
Icons.person,
size: 60,
color: Colors.blue[600],
),
),
SizedBox(height: 20),
// 姓名
Text(
'张三',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.grey[800],
),
),
SizedBox(height: 8),
// 职位
Text(
'Flutter开发工程师',
style: TextStyle(
fontSize: 16,
color: Colors.grey[600],
),
),
SizedBox(height: 20),
// 联系方式
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildContactButton(
icon: Icons.phone,
label: '电话',
color: Colors.green,
),
_buildContactButton(
icon: Icons.email,
label: '邮箱',
color: Colors.blue,
),
_buildContactButton(
icon: Icons.location_on,
label: '地址',
color: Colors.red,
),
],
),
SizedBox(height: 20),
// 个人简介
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
),
child: Text(
'热爱编程,专注于移动应用开发。'
'拥有3年Flutter开发经验,'
'致力于创造优秀的用户体验。',
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
height: 1.5,
),
textAlign: TextAlign.center,
),
),
],
),
),
),
);
}
Widget _buildContactButton({
required IconData icon,
required String label,
required Color color,
}) {
return Column(
children: [
Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: color, size: 24),
),
SizedBox(height: 4),
Text(
label,
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
);
}
}
学习总结
通过这一章的学习,你已经掌握了:
- Widget概念:理解了一切皆Widget的思想
- StatelessWidget vs StatefulWidget:知道了静态和动态组件的区别
- 基础Widget:学会了Text、Image、Icon、Container、Button的使用
恭喜你完成了Flutter基础概念的学习!🎉 现在你已经掌握了Flutter开发的基础积木,可以开始构建更复杂的应用了!
更多推荐

所有评论(0)