<返回目录     Powered by claud/xia兄

第5课:常用组件实战应用

Text、Image、Button、TextField、Icon、Card等核心组件

📋 学习前提

🎯 课程目标

通过本课程,你将能够:

🚀 Flutter组件生态系统

Flutter提供了丰富的组件库,主要分为两大类:

Material Design组件

Cupertino组件(iOS风格)

💡 重要概念:组件组合

Flutter的核心思想是通过组合简单组件来构建复杂界面。每个组件都是独立的,可以自由组合和重用。

📝 Text(文本组件)

Text的基本用法

Text是显示文本内容的核心组件:

import 'package:flutter/material.dart'; class TextExample extends StatelessWidget { @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 基本文本 const Text('普通文本'), // 带样式的文本 const Text( '带样式文本', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue, decoration: TextDecoration.underline, ), ), // 多行文本 const Text( '这是一个很长的文本内容,会自动换行显示。Flutter的文本组件支持丰富的样式和排版功能。', style: TextStyle(fontSize: 16), maxLines: 2, overflow: TextOverflow.ellipsis, // 超出显示省略号 ), // 富文本(RichText) Text.rich( TextSpan( children: [ const TextSpan( text: '红色', style: TextStyle(color: Colors.red, fontSize: 20), ), const TextSpan(text: '和'), const TextSpan( text: '蓝色', style: TextStyle(color: Colors.blue, fontSize: 20), ), const TextSpan(text: '的文本'), WidgetSpan( child: Icon(Icons.star, color: Colors.amber, size: 20), ), ], ), ), ], ); } }

TextStyle常用属性

TextStyle( color: Colors.black, // 文字颜色 fontSize: 16.0, // 字体大小 fontWeight: FontWeight.bold, // 字体粗细 fontStyle: FontStyle.italic, // 字体样式(斜体) letterSpacing: 1.0, // 字符间距 wordSpacing: 2.0, // 单词间距 height: 1.5, // 行高 backgroundColor: Colors.yellow, // 背景颜色 decoration: TextDecoration.underline, // 装饰线 decorationColor: Colors.red, // 装饰线颜色 decorationStyle: TextDecorationStyle.dashed, // 装饰线样式 shadows: [ // 文字阴影 Shadow( color: Colors.grey, blurRadius: 2, offset: Offset(2, 2), ), ], )
💡 最佳实践:文本主题

使用Theme.of(context).textTheme来获取主题中的文本样式,保持应用风格的一致性。

🖼️ Image(图片组件)

图片加载方式

Flutter支持多种图片加载方式:

Column( children: [ // 1. 加载本地图片 Image.asset( 'assets/images/avatar.png', width: 100, height: 100, fit: BoxFit.cover, ), // 2. 加载网络图片 Image.network( 'https://example.com/image.jpg', width: 200, height: 150, fit: BoxFit.contain, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ); }, ), // 3. 加载内存中的图片 Image.memory( Uint8List.fromList([...]), // 图片字节数据 width: 100, height: 100, ), // 4. 加载文件图片 Image.file( File('/path/to/image.jpg'), width: 100, height: 100, ), ], )

图片适配模式(BoxFit)

图片装饰和效果

// 圆形头像 Container( width: 80, height: 80, decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( image: NetworkImage('https://example.com/avatar.jpg'), fit: BoxFit.cover, ), border: Border.all(color: Colors.white, width: 2), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.3), blurRadius: 8, offset: Offset(0, 4), ), ], ), ) // 带占位符和错误处理的图片 FadeInImage.assetNetwork( placeholder: 'assets/placeholder.jpg', // 占位图 image: 'https://example.com/image.jpg', // 网络图 width: 200, height: 150, fit: BoxFit.cover, imageErrorBuilder: (context, error, stackTrace) { return Icon(Icons.error, color: Colors.red, size: 50); }, )

🔘 Button(按钮组件)

按钮类型和使用场景

ElevatedButton

凸起按钮,主要操作

TextButton

文本按钮,次要操作

OutlinedButton

轮廓按钮,中等重要性

IconButton

图标按钮,工具栏

Column( children: [ // ElevatedButton - 凸起按钮 ElevatedButton( onPressed: () { print('按钮被点击'); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), elevation: 4, ), child: Text('主要按钮'), ), SizedBox(height: 10), // TextButton - 文本按钮 TextButton( onPressed: () { print('文本按钮被点击'); }, style: TextButton.styleFrom( foregroundColor: Colors.blue, padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), child: Text('次要按钮'), ), SizedBox(height: 10), // OutlinedButton - 轮廓按钮 OutlinedButton( onPressed: () { print('轮廓按钮被点击'); }, style: OutlinedButton.styleFrom( foregroundColor: Colors.blue, side: BorderSide(color: Colors.blue, width: 1), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Text('轮廓按钮'), ), SizedBox(height: 10), // IconButton - 图标按钮 IconButton( onPressed: () { print('图标按钮被点击'); }, icon: Icon(Icons.favorite), color: Colors.red, iconSize: 30, ), SizedBox(height: 10), // 带图标的按钮 ElevatedButton.icon( onPressed: () {}, icon: Icon(Icons.send), label: Text('发送'), style: ElevatedButton.styleFrom( backgroundColor: Colors.green, ), ), ], )

按钮状态管理

class ButtonStateExample extends StatefulWidget { @override _ButtonStateExampleState createState() => _ButtonStateExampleState(); } class _ButtonStateExampleState extends State { bool _isLoading = false; void _simulateApiCall() async { setState(() { _isLoading = true; }); // 模拟API调用 await Future.delayed(Duration(seconds: 2)); setState(() { _isLoading = false; }); } @override Widget build(BuildContext context) { return ElevatedButton( onPressed: _isLoading ? null : _simulateApiCall, // 禁用状态 child: _isLoading ? SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : Text('提交'), ); } }

📋 TextField(输入框组件)

TextField的基本用法

class TextFieldExample extends StatefulWidget { @override _TextFieldExampleState createState() => _TextFieldExampleState(); } class _TextFieldExampleState extends State { final TextEditingController _controller = TextEditingController(); String _inputText = ''; @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: [ // 基本输入框 TextField( controller: _controller, decoration: InputDecoration( labelText: '用户名', hintText: '请输入用户名', prefixIcon: Icon(Icons.person), border: OutlineInputBorder(), ), onChanged: (value) { setState(() { _inputText = value; }); }, ), SizedBox(height: 20), // 密码输入框 TextField( obscureText: true, // 隐藏文本 decoration: InputDecoration( labelText: '密码', hintText: '请输入密码', prefixIcon: Icon(Icons.lock), suffixIcon: IconButton( icon: Icon(Icons.visibility), onPressed: () {}, ), border: OutlineInputBorder(), ), ), SizedBox(height: 20), // 多行文本输入 TextField( maxLines: 3, decoration: InputDecoration( labelText: '个人简介', hintText: '请输入个人简介...', border: OutlineInputBorder(), ), ), SizedBox(height: 20), Text('输入的内容: $_inputText'), ], ); } }

输入验证和格式化

TextField( decoration: InputDecoration( labelText: '邮箱', errorText: _emailError, border: OutlineInputBorder(), ), keyboardType: TextInputType.emailAddress, onChanged: (value) { // 邮箱验证 bool isValid = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value); setState(() { _emailError = isValid ? null : '请输入有效的邮箱地址'; }); }, ) // 数字输入框 TextField( decoration: InputDecoration( labelText: '年龄', border: OutlineInputBorder(), ), keyboardType: TextInputType.number, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, // 只允许数字 ], )

⭐ Icon和Card组件

Icon(图标组件)

Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Icon(Icons.star, color: Colors.amber, size: 30), Icon(Icons.favorite, color: Colors.red, size: 30), Icon(Icons.thumb_up, color: Colors.blue, size: 30), Icon(Icons.share, color: Colors.green, size: 30), Icon(Icons.delete, color: Colors.grey, size: 30), ], ) // 自定义图标 Icon( Icons.abc, // Material Icons color: Colors.purple, size: 40, ) // 使用图片作为图标 ImageIcon( AssetImage('assets/icons/custom.png'), color: Colors.orange, size: 30, )

Card(卡片组件)

Card( elevation: 4, // 阴影深度 shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.account_circle, size: 40, color: Colors.blue), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('张三', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), Text('前端工程师', style: TextStyle(color: Colors.grey)), ], ), ), Icon(Icons.more_vert, color: Colors.grey), ], ), SizedBox(height: 12), Text('这是一个用户信息卡片,展示了Flutter Card组件的使用方式。'), SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () {}, child: Text('取消'), ), SizedBox(width: 8), ElevatedButton( onPressed: () {}, child: Text('确认'), ), ], ), ], ), ), )

📚 实践练习

练习1:创建用户注册表单

使用各种表单组件创建完整的注册界面:

  1. 用户名输入框(带验证)
  2. 邮箱输入框(格式验证)
  3. 密码输入框(显示/隐藏功能)
  4. 确认密码输入框(一致性验证)
  5. 提交按钮(加载状态)

练习2:实现商品卡片组件

使用Card和布局组件创建商品展示卡片:

  1. 商品图片展示
  2. 商品标题和描述
  3. 价格和折扣信息
  4. 评分和购买按钮
  5. 添加收藏和分享功能

练习3:构建设置页面

使用各种交互组件创建设置界面:

  1. 开关控件(通知设置)
  2. 单选按钮(主题选择)
  3. 下拉选择框(语言设置)
  4. 滑块控件(音量调节)
  5. 按钮组(操作确认)

🔍 常见问题解答

Q: 如何自定义按钮的样式?

A: 使用ButtonStyle或对应的styleFrom方法,可以设置颜色、形状、内边距等属性。

Q: TextField如何获取输入的值?

A: 使用TextEditingController或onChanged回调来获取输入值。

Q: 图片加载失败怎么办?

A: 使用errorBuilder属性或FadeInImage组件来处理加载失败的情况。

Q: 如何实现表单验证?

A: 结合TextFormField和Form组件,使用validator属性进行验证。

📖 总结

在本课程中,我们深入学习了Flutter的核心UI组件:

这些组件是构建Flutter应用的基础,熟练掌握它们将帮助你快速开发出功能完善、界面美观的应用程序。