文章目录
-
- 🎯先搞懂:自定义类到底解决什么问题?
- 📝拆解FileItem:自定义类的核心写法
-
- 1. 类的基础结构:class + 类名
- 2. 核心属性:用late final定义“不可变的延迟变量”
- 3. 构造函数:给类“传值”的入口
- 🚀实战场景:自定义类的3个高频用法
-
- 场景1:作为ListView的数据源(最核心)
- 场景2:作为函数参数/返回值
- 场景3:扩展功能(易维护)
- ⚠️新手必避的3个坑
- 📌进阶优化(小白也能试)
-
- 总结
在构建文本管理模块中,设计到一个自定义类的概念。今天就以它为范本,从应用场景→核心写法→实战用法→避坑指南,把自定义类讲得透透的,新手也能一看就会!
🎯先搞懂:自定义类到底解决什么问题?
在讲FileItem之前,先回答新手最核心的疑问:为什么要写自定义类?
假设你要做一个文件管理APP的列表页面,需要展示每个文件的「名称、类型、大小、日期」。如果不用自定义类,你可能会这样写:
// 新手踩坑写法:数据零散,维护灾难
String file1Title = "旅行照片.jpg";
String file1Category = "图片";
String file1Size = "2.5MB";
String file1Date = "2024-03-10";
String file2Title = "项目文档.pdf";
String file2Category = "文档";
String file2Size = "1.8MB";
String file2Date = "2024-03-09";
// …新增100个文件就要写400行代码!
数据分散在无数变量里,增删文件要改N处,还容易出现“文件名和大小对应不上”的低级错误。
而自定义FileItem类,就是把关联的一组数据打包成一个“数据容器”,让代码从“散装”变“精装”——这也是Flutter开发中自定义类最核心的价值!
📝拆解FileItem:自定义类的核心写法
先贴完整代码,我们逐行拆解,新手也能秒懂:
class FileItem {
// 1. 定义类的属性:存储文件的核心信息
late final String title; // 文件名
late final String category;// 文件分类
late final String size; // 文件大小
late final String date; // 文件日期
// 2. 构造函数:初始化属性
FileItem(this.title, this.category, this.size, this.date);
}
1. 类的基础结构:class + 类名
class FileItem { ... }
- class:Dart定义类的关键字,相当于“创建一个新的数据类型”;
- FileItem:类名遵循“大驼峰命名法”(首字母大写,每个单词首字母大写),见名知意——代表“一个文件项”,这是Flutter的命名规范,新手一定要养成习惯。
2. 核心属性:用late final定义“不可变的延迟变量”
late final String title;
这是新手最容易卡壳的点,拆成两部分讲:
- final:表示属性一旦赋值就不能修改。比如文件名称确定后不会变,用final能避免代码意外修改数据(比如把“旅行照片.jpg”改成“xxx.txt”),减少bug;
- late:表示延迟初始化。Dart要求“非空属性必须初始化”,late告诉编译器:“这个属性我会在创建对象时赋值,你先别报错”。
3. 构造函数:给类“传值”的入口
FileItem(this.title, this.category, this.size, this.date);
这是Dart的“简洁构造函数”,作用是:创建FileItem对象时,把传入的参数直接赋值给对应属性。
新手可以把构造函数理解成“给容器装东西的入口”,比如:
// 创建一个FileItem对象(给容器装数据)
FileItem photoFile = FileItem(
"旅行照片.jpg", // 对应title
"图片", // 对应category
"2.5MB", // 对应size
"2024-03-10" // 对应date
);
现在,photoFile就是一个完整的“文件对象”,想拿哪个信息直接调:
print(photoFile.title); // 输出:旅行照片.jpg
print(photoFile.size); // 输出:2.5MB
数据再也不会乱!
🚀实战场景:自定义类的3个高频用法
以FileItem为例,自定义类在Flutter中最常用的3个场景,新手直接套用就行:
场景1:作为ListView的数据源(最核心)
Flutter的列表(ListView)需要“结构化数据源”,List<FileItem>是最佳选择:
// 1. 定义文件列表数据源
List<FileItem> fileList = [
FileItem("旅行照片.jpg", "图片", "2.5MB", "2024-03-10"),
FileItem("项目文档.pdf", "文档", "1.8MB", "2024-03-09"),
FileItem("短视频.mp4", "视频", "50MB", "2024-03-08"),
];
// 2. 用ListView展示
Widget build(BuildContext context) {
return ListView.builder(
itemCount: fileList.length, // 列表项数量
itemBuilder: (context, index) {
FileItem currentFile = fileList[index]; // 取出当前文件对象
// 构建列表项UI
return ListTile(
title: Text(currentFile.title), // 文件名
subtitle: Text("${currentFile.category} | ${currentFile.size}"), // 类型+大小
trailing: Text(currentFile.date), // 日期
);
},
);
}
运行效果:一个整洁的文件列表,增删文件只需要修改fileList,不用动UI代码——这就是“数据和UI分离”的精髓!
场景2:作为函数参数/返回值
如果需要写一个“筛选图片文件”的函数,自定义类能让参数/返回值更清晰:
// 筛选指定分类的文件
List<FileItem> filterFileByCategory(List<FileItem> allFiles, String targetCategory) {
List<FileItem> result = [];
for (var file in allFiles) {
if (file.category == targetCategory) {
result.add(file);
}
}
return result;
}
// 调用函数:筛选所有图片文件
List<FileItem> imageFiles = filterFileByCategory(fileList, "图片");
print("图片文件数量:${imageFiles.length}"); // 输出:1
如果不用自定义类,这个函数需要传4个列表(标题、分类、大小、日期),返回也得返回4个列表——想想都头大!
场景3:扩展功能(易维护)
如果后续想给文件加“是否收藏”功能,只需要在FileItem里加一行代码:
class FileItem {
late final String title;
late final String category;
late final String size;
late final String date;
late final bool isCollected; // 新增:是否收藏
// 构造函数同步加参数
FileItem(this.title, this.category, this.size, this.date, this.isCollected);
}
// 创建带收藏属性的文件对象
FileItem collectedFile = FileItem("重要笔记.txt", "文档", "1KB", "2024-03-10", true);
所有使用FileItem的地方都能直接用isCollected属性,不用到处改代码——这就是自定义类的“可扩展性”!
⚠️新手必避的3个坑
滥用late导致崩溃 late的本质是“延迟初始化”,如果创建对象时漏传参数,运行时会直接崩溃:
// 错误示例:少传date参数
FileItem wrongFile = FileItem("错误文件.txt", "文档", "1KB");
// 调用wrongFile.date时崩溃!
✅ 解决:要么确保构造函数参数全传,要么用“可选参数”优化构造函数:
// 优化:可选参数+默认值
FileItem({
required this.title,
required this.category,
required this.size,
this.date = "未知日期", // 可选参数,默认值
});
// 调用:date可选传
FileItem file = FileItem(title: "笔记.txt", category: "文档", size: "1KB");
final属性想修改却改不了 final是“只读”的,如果需要修改文件名(比如重命名),要去掉final:
// 可修改的属性
String title; // 去掉final,支持file.title = "新名称.jpg"
类名/属性名命名不规范 新手别写class fileitem(小写)、String t(无意义),一定要见名知意: ❌ 错误:class fileitem { String t; String c; } ✅ 正确:class FileItem { String title; String category; }
📌进阶优化(小白也能试)
给FileItem加一个“打印信息”的方法,调试更方便:
class FileItem {
late final String title;
late final String category;
late final String size;
late final String date;
FileItem(this.title, this.category, this.size, this.date);
// 新增:打印文件信息
void printFileInfo() {
print("【文件信息】名称:$title | 类型:$category | 大小:$size | 日期:$date");
}
}
// 使用
FileItem myFile = FileItem("笔记.txt", "文档", "500KB", "2024-03-10");
myFile.printFileInfo(); // 控制台输出清晰的文件信息