一、字重设置不生效
1.1 问题现象
设置页面提供了四档字重选项(细、正常、中粗、粗),但除了”粗”之外,其他三档视觉上没有任何区别。
1.2 原因分析
原来的实现:
static TextTheme _applyFontWeight(TextTheme base, FontWeight weight, Color color) {
return base.apply(fontWeightDelta: 0).copyWith(
displayLarge: base.displayLarge?.copyWith(fontWeight: weight, color: color),
// ...
);
}问题:copyWith(fontWeight: ...) 只是修改了样式属性,但不会加载对应字重的字体文件。
Google Fonts 的 Noto Sans SC 实际上每个字重是独立的字体文件:
NotoSansSC-Light.ttf(300)NotoSansSC-Regular.ttf(400)NotoSansSC-Medium.ttf(500)NotoSansSC-SemiBold.ttf(600)
1.3 解决方案
直接使用 GoogleFonts.notoSansSc(fontWeight: weight) 生成每个 TextStyle:
static TextTheme _buildTextTheme(TextTheme base, FontWeight weight, Color color) {
return TextTheme(
displayLarge: GoogleFonts.notoSansSc(
textStyle: base.displayLarge,
fontWeight: weight,
color: color,
),
displayMedium: GoogleFonts.notoSansSc(
textStyle: base.displayMedium,
fontWeight: weight,
color: color,
),
// ... 所有 14 个 TextStyle 都使用 GoogleFonts.notoSansSc 直接生成
);
}关键理解:GoogleFonts.notoSansSc() 会根据 fontWeight 参数自动加载对应的字体文件。
二、文件图标颜色消失
2.1 问题现象
聊天界面发送文件后,文件消息的图标颜色不显示(灰色),而之前是有颜色的。
2.2 原因分析
FileMessageContent._buildFileIcon() 方法内部使用了固定颜色,而没有使用传入的 iconColor 参数:
// 问题代码
Widget _buildFileIcon(ThemeData theme, Color accentColor) {
return Container(
decoration: BoxDecoration(
color: accentColor.withValues(alpha: 0.2), // 使用了 accentColor 而非 iconColor
// ...
),
child: Icon(icon, color: accentColor, size: 24), // 同样问题
);
}2.3 解决方案
修改为使用传入的 iconColor 参数:
Widget _buildFileIcon(ThemeData theme, Color accentColor) {
final displayColor = iconColor; // 使用传入的颜色
return Container(
decoration: BoxDecoration(
color: displayColor.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: displayColor, size: 24),
);
}三、图片上传后缩略图无法加载
3.1 问题现象
聊天界面上传图片后,缩略图显示加载占位符,无法正常显示。但重新进入聊天界面后又能正常显示。
3.2 原因分析
这是一个之前解决过的问题(参见 memory: ImagePicker返回文件可能无扩展名)。
ImagePicker 在某些情况下返回的文件名没有扩展名(如 image_picker_xxxxx),而我们的文件类型判断依赖扩展名:
// 问题:safeFileName 可能没有扩展名
if (isImageFile(safeFileName)) {
// 无法匹配,走不到这里
}3.3 解决方案
同时检查文件名和文件路径:
if (isVideoFile(safeFileName) || isVideoFile(filePath)) {
// 处理视频
} else if (isImageFile(safeFileName) || isImageFile(filePath)) {
// 处理图片
}原理:即使 safeFileName 没有扩展名,filePath(完整路径)通常包含正确的扩展名。
四、修改文件清单
4.1 app_theme.dart
- 将
_applyFontWeight()改为_buildTextTheme() - 使用
GoogleFonts.notoSansSc()直接生成带字重的 TextStyle
4.2 chat_widgets.dart
- 修复
FileMessageContent._buildFileIcon()使用正确的iconColor参数
4.3 chat_page.dart(或相关文件)
- 文件类型判断时同时检查
fileName和filePath
五、经验教训
5.1 Google Fonts 字重加载
copyWith(fontWeight: ...) 只修改样式属性,不会触发字体文件加载。
必须使用 GoogleFonts.xxx(fontWeight: weight) 才能加载对应字重的字体文件。
5.2 ImagePicker 文件名问题
ImagePicker 返回的文件名可能:
- 没有扩展名
- 使用临时文件名(如
image_picker_xxxxx) - 实际文件路径才有正确扩展名
最佳实践:使用 ensureFileExtensionAsync(fileName, filePath) 确保文件名有正确扩展名。
5.3 参数传递检查
当组件显示不符合预期时,检查:
- 参数是否正确传递
- 内部是否使用了传入的参数(而非其他变量)