feat(mobile): UI-01 theme system, shared components and navigation
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/// 网络照片缩略图(UI-01 §4.1):固定宽高比预留 + 占位 + 失败替代图。
|
||||
///
|
||||
/// 布局稳定性优先:占位不是转圈,而是同一宽高比的中性色块(网格/卡片
|
||||
/// 不因加载状态跳动);加载完成前显示占位,失败显示中性色块 + 小图标
|
||||
/// (不显示破图)。[url] 为 null(无封面/已删除)时常驻占位。使用
|
||||
/// Image.network + errorBuilder(项目未引入 cached_network_image,保持
|
||||
/// 零新增依赖)。
|
||||
library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 网络缩略图:`AspectRatio` 包裹,cover 裁切。
|
||||
class PhotoThumbnail extends StatelessWidget {
|
||||
const PhotoThumbnail({
|
||||
required this.url,
|
||||
required this.aspectRatio,
|
||||
this.fit = BoxFit.cover,
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// 图片 URL;null 显示常驻占位(无封面/无预览语义)。
|
||||
final String? url;
|
||||
|
||||
/// 宽高比(相册封面 16:9、网格 1:1 等)——占位与图片共用,尺寸恒定。
|
||||
final double aspectRatio;
|
||||
|
||||
/// 图片适配(默认 cover 裁切;大图查看用 contain)。
|
||||
final BoxFit fit;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (url == null) {
|
||||
return AspectRatio(
|
||||
aspectRatio: aspectRatio,
|
||||
child: _placeholder(context),
|
||||
);
|
||||
}
|
||||
return AspectRatio(
|
||||
aspectRatio: aspectRatio,
|
||||
child: Image.network(
|
||||
url!,
|
||||
fit: fit,
|
||||
// 帧 ready 前显示中性占位(不是 spinner):布局稳定优先。
|
||||
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) =>
|
||||
wasSynchronouslyLoaded || frame != null
|
||||
? child
|
||||
: _placeholder(context),
|
||||
errorBuilder: (_, _, _) =>
|
||||
_placeholder(context, icon: Icons.broken_image_outlined),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 中性占位色块 + 小图标(加载中 / 无封面 / 加载失败共用)。
|
||||
Widget _placeholder(
|
||||
BuildContext context, {
|
||||
IconData icon = Icons.image_outlined,
|
||||
}) {
|
||||
final theme = Theme.of(context);
|
||||
return ColoredBox(
|
||||
color: theme.colorScheme.surfaceContainerHighest,
|
||||
child: Center(
|
||||
child: Icon(icon, size: 24, color: theme.colorScheme.onSurfaceVariant),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user