chatapp3-flutter/lib/modules/media/image_preview_page.dart
2026-04-09 21:32:23 +08:00

149 lines
4.4 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:io';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'package:photo_view/photo_view_gallery.dart';
import 'package:yumi/app/constants/sc_global_config.dart';
class ImagePreviewPage extends StatefulWidget {
final List<String> imageUrls;
final int initialIndex;
final PageController? pageController;
const ImagePreviewPage({
Key? key,
required this.imageUrls,
this.initialIndex = 0,
this.pageController,
}) : super(key: key);
@override
_ImagePreviewPageState createState() => _ImagePreviewPageState();
}
class _ImagePreviewPageState extends State<ImagePreviewPage> {
late PageController _pageController;
late int _currentIndex;
bool _showAppBar = true;
@override
void initState() {
super.initState();
_currentIndex = widget.initialIndex;
_pageController =
widget.pageController ??
PageController(initialPage: widget.initialIndex);
}
void _onPageChanged(int index) {
setState(() {
_currentIndex = index;
});
}
void _toggleAppBar() {
setState(() {
_showAppBar = !_showAppBar;
});
}
void _onTap() {
_toggleAppBar();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: SCGlobalConfig.businessLogicStrategy.getImagePreviewBackgroundColor(),
body: Stack(
children: [
// 图片画廊
PhotoViewGallery.builder(
scrollPhysics: const BouncingScrollPhysics(),
builder: _buildImage,
itemCount: widget.imageUrls.length,
loadingBuilder:
(context, event) => Center(
child: Container(
width: 20.0,
height: 20.0,
child: CircularProgressIndicator(
value:
event == null
? 0
: event.cumulativeBytesLoaded /
event.expectedTotalBytes!,
color: SCGlobalConfig.businessLogicStrategy.getImagePreviewLoadingIndicatorColor(),
),
),
),
backgroundDecoration: BoxDecoration(color: SCGlobalConfig.businessLogicStrategy.getImagePreviewGalleryBackgroundColor()),
pageController: _pageController,
onPageChanged: _onPageChanged,
enableRotation: true,
customSize: MediaQuery.of(context).size,
),
// 顶部应用栏
if (_showAppBar) _buildAppBar(),
],
),
);
}
PhotoViewGalleryPageOptions _buildImage(BuildContext context, int index) {
final imageUrl = widget.imageUrls[index];
return PhotoViewGalleryPageOptions(
imageProvider: _getImageProvider(imageUrl),
initialScale: PhotoViewComputedScale.contained,
minScale: PhotoViewComputedScale.contained * 0.8,
maxScale: PhotoViewComputedScale.covered * 2.0,
heroAttributes: PhotoViewHeroAttributes(tag: imageUrl),
onTapUp: (_, __, ___) => _onTap(),
);
}
ImageProvider _getImageProvider(String imageUrl) {
if (imageUrl.startsWith('http')) {
return ExtendedNetworkImageProvider(
imageUrl,
cache: true, // 启用缓存默认即为true
cacheMaxAge: Duration(days: 7), // 设置缓存有效期
);
} else {
return FileImage(File(imageUrl));
}
}
Widget _buildAppBar() {
return Positioned(
top: 0,
left: 0,
right: 0,
child: AppBar(
backgroundColor: SCGlobalConfig.businessLogicStrategy.getImagePreviewAppBarBackgroundColor(),
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: SCGlobalConfig.businessLogicStrategy.getImagePreviewBackIconColor()),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
'${_currentIndex + 1} / ${widget.imageUrls.length}',
style: TextStyle(color: SCGlobalConfig.businessLogicStrategy.getImagePreviewTextColor()),
),
centerTitle: true,
),
);
}
@override
void dispose() {
if (widget.pageController == null) {
_pageController.dispose();
}
super.dispose();
}
}