feat:更新菜谱显示模块

This commit is contained in:
2025-11-18 15:57:00 +08:00
parent df26790389
commit 9a8e1a7419
9 changed files with 244 additions and 221 deletions

View File

@@ -19,6 +19,7 @@ class ImagePreviewPage extends StatefulWidget {
class _ImagePreviewPageState extends State<ImagePreviewPage> {
// 声明 PageController 并初始化初始索引
late PageController _pageController;
// 记录当前显示的图片索引(用于更新页码)
int _currentIndex = 0;
@@ -68,17 +69,18 @@ class _ImagePreviewPageState extends State<ImagePreviewPage> {
centerTitle: true,
),
body: PhotoViewGallery(
pageOptions: widget.images.map((url) {
return PhotoViewGalleryPageOptions(
imageProvider: NetworkImage(url),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
// 点击空白处关闭预览
onTapDown: (context, details, controllerValue) {
Navigator.pop(context);
},
);
}).toList(),
pageOptions:
widget.images.map((url) {
return PhotoViewGalleryPageOptions(
imageProvider: NetworkImage(url),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
// 点击空白处关闭预览
onTapDown: (context, details, controllerValue) {
Navigator.pop(context);
},
);
}).toList(),
pageController: _pageController,
scrollDirection: Axis.horizontal,
),
@@ -86,30 +88,94 @@ class _ImagePreviewPageState extends State<ImagePreviewPage> {
}
}
Widget buildNetworkImage(String url) {
Widget buildNetworkImage(BuildContext context, String url) {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
url,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
// 加载中显示占位符
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
);
child: GestureDetector(
onTap: () {
_showFullScreenImage(context, url);
},
errorBuilder: (context, error, stackTrace) {
return Container(
color: Colors.grey[200],
child: const Icon(Icons.image, color: Colors.grey, size: 30),
child: Image.network(
url,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return _buildLoadingIndicator(loadingProgress);
},
errorBuilder: (context, error, stackTrace) => _buildErrorImage(),
),
),
);
}
Widget _buildLoadingIndicator(ImageChunkEvent? loadingProgress) {
return Center(
child: SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(
value:
loadingProgress?.expectedTotalBytes != null
? loadingProgress!.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
),
);
}
Widget _buildErrorImage() {
return Container(
color: Colors.grey[200],
child: const Icon(Icons.image, color: Colors.grey, size: 30),
);
}
Widget _buildPhotoView(String url) {
return PhotoView(
imageProvider: NetworkImage(url),
backgroundDecoration: const BoxDecoration(color: Colors.transparent),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
initialScale: PhotoViewComputedScale.contained,
heroAttributes: PhotoViewHeroAttributes(tag: url),
loadingBuilder: (context, event) => _buildLoadingIndicator(event),
errorBuilder: (context, error, stackTrace) => _buildErrorImage(),
);
}
Widget _buildCloseImage(BuildContext context) {
return Positioned(
top: MediaQuery.of(context).padding.top + 10,
right: 20,
child: IconButton(
icon: Icon(Icons.close, color: Colors.white, size: 30),
onPressed: () => Navigator.of(context).pop(),
),
);
}
void _showFullScreenImage(BuildContext context, String url) {
Navigator.of(context).push(
PageRouteBuilder(
opaque: false,
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return Scaffold(
backgroundColor: Colors.black.withAlpha(200),
body: Stack(
children: [
// 可缩放图片
Positioned.fill(child: _buildPhotoView(url)),
// 关闭按钮
_buildCloseImage(context),
],
),
);
},
),
);
}
}

View File

@@ -83,7 +83,7 @@ Widget circleIconButton({
required IconData icon,
required VoidCallback onPressed,
required BuildContext context,
bool? isSmall
bool? isSmall,
}) {
final double size = isSmall == true ? 24 : 36;
@@ -101,6 +101,19 @@ Widget circleIconButton({
);
}
Widget buildTag(BuildContext context, String title) {
final colors = Theme.of(context).colorScheme;
return Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: Color.lerp(colors.primary, Colors.white, 0.8),
borderRadius: BorderRadius.circular(10),
),
child: Text(title, style: TextStyle(color: colors.primary)),
);
}
/// 确认按钮样式
ButtonStyle primaryButtonStyle() {
return ButtonStyle(

View File

@@ -94,7 +94,6 @@ class _YearSelectorState extends State<YearSelector>
isSmall: true,
onPressed: () => _previousYear(),
),
SizedBox(width: 5),
// 年份显示
AnimatedBuilder(
animation: _scaleAnimation,
@@ -110,7 +109,6 @@ class _YearSelectorState extends State<YearSelector>
),
),
),
SizedBox(width: 5),
circleIconButton(
context: context,
icon: Icons.chevron_right,