7969bb41e3
抽出共享全屏查看器 fullscreen_image_viewer.dart(复用扫码页的 InteractiveViewer+PageView+黑底 modal),详情页缩略图双击打开, 扫码公开页改为复用同一组件去重。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
87 lines
2.6 KiB
Dart
87 lines
2.6 KiB
Dart
import 'package:flutter/material.dart';
|
||
|
||
/// 全屏图片查看器:黑底 modal + 多图左右翻页(PageView)+ 双指缩放/拖拽(InteractiveViewer)。
|
||
/// 点击背景或右上角关闭按钮退出。纯 Flutter 内置组件,无需额外依赖。
|
||
///
|
||
/// 用法:
|
||
/// ```dart
|
||
/// showFullscreenImages(context, urls, initialIndex: 2);
|
||
/// ```
|
||
void showFullscreenImages(BuildContext context, List<String> urls,
|
||
{int initialIndex = 0}) {
|
||
if (urls.isEmpty) return;
|
||
Navigator.of(context).push(PageRouteBuilder(
|
||
opaque: false,
|
||
barrierColor: Colors.black87,
|
||
pageBuilder: (_, __, ___) =>
|
||
FullscreenImageViewer(urls: urls, initialIndex: initialIndex),
|
||
));
|
||
}
|
||
|
||
class FullscreenImageViewer extends StatefulWidget {
|
||
final List<String> urls;
|
||
final int initialIndex;
|
||
const FullscreenImageViewer(
|
||
{super.key, required this.urls, this.initialIndex = 0});
|
||
|
||
@override
|
||
State<FullscreenImageViewer> createState() => _FullscreenImageViewerState();
|
||
}
|
||
|
||
class _FullscreenImageViewerState extends State<FullscreenImageViewer> {
|
||
late PageController _ctrl;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_ctrl = PageController(initialPage: widget.initialIndex);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_ctrl.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return GestureDetector(
|
||
onTap: () => Navigator.of(context).pop(),
|
||
child: Scaffold(
|
||
backgroundColor: Colors.transparent,
|
||
body: Stack(
|
||
children: [
|
||
PageView.builder(
|
||
controller: _ctrl,
|
||
itemCount: widget.urls.length,
|
||
itemBuilder: (_, i) => Center(
|
||
child: InteractiveViewer(
|
||
child: Image.network(widget.urls[i], fit: BoxFit.contain,
|
||
errorBuilder: (_, __, ___) => const Icon(
|
||
Icons.broken_image,
|
||
size: 64,
|
||
color: Colors.white54)),
|
||
),
|
||
),
|
||
),
|
||
Positioned(
|
||
top: 40,
|
||
right: 16,
|
||
child: GestureDetector(
|
||
onTap: () => Navigator.of(context).pop(),
|
||
child: Container(
|
||
padding: const EdgeInsets.all(8),
|
||
decoration: BoxDecoration(
|
||
color: Colors.black54,
|
||
borderRadius: BorderRadius.circular(20)),
|
||
child: const Icon(Icons.close, color: Colors.white, size: 20),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|