
作者:爱吃大芒果
个人主页 爱吃大芒果
本文所属专栏 Flutter
更多专栏
Ascend C 算子开发教程(进阶) 鸿蒙集成 从0到1自学C++
Text、Image、Button 是 Flutter 最核心的基础 UI 组件,掌握其核心属性和实用技巧能大幅提升开发效率。本文将从基础用法、核心属性、实战技巧三个维度拆解这三个组件。
Text 用于展示静态/动态文本,核心是通过 TextStyle 控制样式,适配不同场景的文本展示需求。
最简化的用法仅需传入文本内容,Flutter 会使用默认样式(系统字体、黑色、14sp 左右):
Text("Hello Flutter");属性名 | 作用 |
|---|---|
style | 文本样式(核心),接收 TextStyle 对象,控制字体、颜色、大小等 |
textAlign | 文本对齐方式(left/center/right/justify 等) |
maxLines | 最大显示行数,超出后结合 overflow 处理 |
overflow | 文本溢出处理(clip/ellipsis/fade),常用 TextOverflow.ellipsis |
softWrap | 是否自动换行(true/false) |
Text(
"Flutter 文本样式示例",
style: TextStyle(
fontSize: 18, // 字体大小
color: Colors.blue, // 字体颜色
fontWeight: FontWeight.bold, // 字体粗细
fontFamily: "PingFangSC", // 自定义字体(需提前配置)
height: 1.5, // 行高(相对于字体大小的倍数)
decoration: TextDecoration.underline, // 下划线(lineThrough/overline)
decorationColor: Colors.red, // 装饰线颜色
letterSpacing: 2.0, // 字间距
),
textAlign: TextAlign.center, // 居中对齐
maxLines: 1, // 仅显示1行
overflow: TextOverflow.ellipsis, // 溢出省略
);单 Text 无法实现多样式混排时,使用 RichText + TextSpan:
RichText(
text: TextSpan(
text: "用户名:",
style: TextStyle(color: Colors.black, fontSize: 16),
children: [
TextSpan(
text: "Flutter 开发者",
style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
// 文本点击事件
recognizer: TapGestureRecognizer()..onTap = () {
print("点击了用户名");
},
),
TextSpan(
text: "(已认证)",
style: TextStyle(color: Colors.green, fontSize: 14),
),
],
),
);长文本超出容器时,用 FittedBox 包裹实现自动缩放:
Container(
width: 200,
height: 50,
color: Colors.grey[100],
child: FittedBox(
fit: BoxFit.scaleDown, // 仅在文本超出时缩放
child: Text("这是一段超长的文本内容,测试自适应缩放效果"),
),
);fonts 文件夹,放入字体文件(如 PingFangSC-Regular.ttf);pubspec.yaml 中配置:flutter:
fonts:
- family: PingFangSC
fonts:
- asset: fonts/PingFangSC-Regular.ttf
- asset: fonts/PingFangSC-Bold.ttf
weight: 700TextStyle 中通过 fontFamily: "PingFangSC" 使用。Image 支持加载本地资源、网络图片、本地文件、内存图片,核心是控制图片适配方式和异常处理。
图片源 | 构造方法 | 示例 |
|---|---|---|
本地资源 | Image.asset() | Image.asset("images/logo.png") |
网络图片 | Image.network() | Image.network("https://xxx.png") |
本地文件 | Image.file() | Image.file(File("/sdcard/xxx.png")) |
内存图片 | Image.memory() | Image.memory(Uint8List bytes) |
属性名 | 作用 |
|---|---|
width/height | 图片宽高(仅设置一个时,按比例缩放) |
fit | 图片适配方式(核心),接收 BoxFit 枚举 |
alignment | 图片对齐方式(默认 Alignment.center) |
repeat | 图片重复方式(ImageRepeat.repeat 等,仅图片小于容器时生效) |
color/colorBlendMode | 图片叠加颜色+混合模式(如灰色滤镜) |
errorBuilder | 图片加载失败时的占位组件 |
loadingBuilder | 图片加载中时的占位组件(仅网络图片) |
cacheWidth/cacheHeight | 缓存图片尺寸(优化性能,避免加载超大图) |
Image.network(
"https://flutter.dev/images/flutter-logo-sharing.png",
width: 200,
height: 200,
// 常用适配方式:
// fit: BoxFit.contain, // 保持比例,完整显示(可能留空白)
// fit: BoxFit.cover, // 保持比例,填满容器(超出裁剪)
// fit: BoxFit.fill, // 拉伸填满(可能变形)
// fit: BoxFit.fitWidth, // 宽度填满,高度按比例
fit: BoxFit.cover,
alignment: Alignment.topCenter, // 顶部居中对齐
// 图片叠加灰色滤镜
color: Colors.grey,
colorBlendMode: BlendMode.color,
);images 文件夹,放入图片(如 logo.png);pubspec.yaml 中配置:flutter:
assets:
- images/ # 加载整个文件夹
# - images/logo.png # 加载单个图片Image.asset("images/logo.png")。ClipRRect 包裹(圆角)ClipRRect(
borderRadius: BorderRadius.circular(10), // 圆角半径
child: Image.network(
"https://xxx.png",
width: 100,
height: 100,
fit: BoxFit.cover,
),
);ClipOval 包裹(圆形,需宽高相等)ClipOval(
child: Image.network(
"https://xxx.png",
width: 100,
height: 100,
fit: BoxFit.cover,
),
);BoxDecoration(推荐,性能更好)Container(
width: 100,
height: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
image: NetworkImage("https://xxx.png"),
fit: BoxFit.cover,
),
),
);原生 Image.network 无缓存,推荐使用 cached_network_image 插件:
flutter pub add cached_network_image;CachedNetworkImage(
imageUrl: "https://xxx.png",
width: 100,
height: 100,
fit: BoxFit.cover,
// 加载中占位
placeholder: (context, url) => CircularProgressIndicator(),
// 加载失败占位
errorWidget: (context, url, error) => Icon(Icons.error, color: Colors.red),
// 缓存配置
cacheManager: CacheManager(
Config(
"custom_cache_key",
maxNrOfCacheObjects: 100, // 最大缓存数
stalePeriod: Duration(days: 7), // 缓存有效期
),
),
);Flutter 提供了三类基础按钮:ElevatedButton(带阴影的凸起按钮)、TextButton(文本按钮)、OutlinedButton(边框按钮),还有 IconButton(图标按钮),核心是 onPressed 回调和样式自定义。
所有按钮的核心是 onPressed(null 时按钮禁用),child 为按钮内容:
// 1. ElevatedButton(凸起按钮)
ElevatedButton(
onPressed: () { // 点击事件
print("ElevatedButton 被点击");
},
child: Text("提交"), // 按钮文本
);
// 2. TextButton(文本按钮,无背景)
TextButton(
onPressed: () {},
child: Text("取消"),
);
// 3. OutlinedButton(边框按钮)
OutlinedButton(
onPressed: () {},
child: Text("编辑"),
);
// 4. IconButton(图标按钮)
IconButton(
icon: Icon(Icons.favorite), // 图标
color: Colors.red, // 图标颜色
onPressed: () {}, // 点击事件
tooltip: "收藏", // 长按提示
);按钮样式通过 style 属性(ButtonStyle)控制,核心配置:
属性名 | 作用 |
|---|---|
backgroundColor | 背景色(ElevatedButton 生效) |
foregroundColor | 前景色(文本/图标颜色) |
side | 边框样式(OutlinedButton 生效) |
shape | 按钮形状(圆角/圆形/矩形) |
padding | 内边距 |
elevation | 阴影高度(ElevatedButton 生效) |
disabledBackgroundColor | 禁用状态背景色 |
ElevatedButton(
onPressed: () {},
child: Text("自定义按钮"),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue, // 背景色
foregroundColor: Colors.white, // 文本颜色
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), // 内边距
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20), // 圆角
// 边框(ElevatedButton 也可加边框)
side: BorderSide(color: Colors.blueAccent, width: 1),
),
elevation: 5, // 阴影高度
minimumSize: Size(100, 44), // 最小尺寸
),
);使用 xxxButton.icon 构造方法,快速实现图标+文本按钮:
ElevatedButton.icon(
onPressed: () {},
icon: Icon(Icons.send, size: 18), // 图标
label: Text("发送"), // 文本
style: ElevatedButton.styleFrom(
shape: CircleBorder(), // 圆形按钮(需设置固定尺寸)
fixedSize: Size(60, 60), // 固定尺寸
),
);高频场景(提交表单)需防止重复点击,通过变量控制:
bool _isClickable = true;
ElevatedButton(
onPressed: _isClickable
? () async {
_isClickable = false; // 禁用按钮
// 模拟接口请求
await Future.delayed(Duration(seconds: 2));
_isClickable = true; // 恢复按钮
setState(() {}); // 更新UI
}
: null, // null 表示禁用
child: Text("提交(防抖)"),
);原生按钮无渐变属性,通过 Container + InkWell 自定义:
Container(
width: 200,
height: 44,
decoration: BoxDecoration(
gradient: LinearGradient( // 渐变背景
colors: [Colors.blue, Colors.purple],
begin: Alignment.left,
end: Alignment.right,
),
borderRadius: BorderRadius.circular(22),
),
child: InkWell( // 水波纹效果
borderRadius: BorderRadius.circular(22),
onTap: () {},
child: Center(
child: Text(
"渐变按钮",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
);避免重复写样式,通过 Theme 统一配置:
Theme(
data: Theme.of(context).copyWith(
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
borderRadius: BorderRadius.circular(8),
),
),
),
child: ElevatedButton(
onPressed: () {},
child: Text("全局样式按钮"),
),
);import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("基础组件示例")),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Image + 圆角
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
"https://flutter.dev/images/flutter-logo-sharing.png",
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
const SizedBox(height: 20),
// Text(富文本)
RichText(
text: const TextSpan(
text: "Flutter ",
style: TextStyle(color: Colors.black, fontSize: 18),
children: [
TextSpan(
text: "基础组件",
style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
),
TextSpan(text: " 实战示例"),
],
),
),
const SizedBox(height: 20),
// Button(自定义样式)
ElevatedButton.icon(
onPressed: () {
print("点击了按钮");
},
icon: const Icon(Icons.info),
label: const Text("查看详情"),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12),
borderRadius: BorderRadius.circular(20),
),
),
],
),
),
),
);
}
}TextStyle 控制样式,富文本用 RichText,长文本注意溢出处理;BoxFit 适配方式,网络图片推荐用缓存插件,圆角优先用 BoxDecoration;ElevatedButton/TextButton,自定义样式用 styleFrom,高频场景加防抖。掌握这些基础用法和技巧,能满足大部分日常 UI 开发需求,后续可结合布局组件(Row/Column/Container)实现更复杂的界面。