image_viewer_page.dart 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import 'package:get/get.dart';
  4. import 'package:keyboard/base/base_page.dart';
  5. import 'package:keyboard/data/bean/image_viewer_item.dart';
  6. import 'package:keyboard/resource/colors.gen.dart';
  7. import 'package:keyboard/resource/string.gen.dart';
  8. import 'package:keyboard/router/app_page_arguments.dart';
  9. import 'package:keyboard/router/app_pages.dart';
  10. import 'package:photo_view/photo_view.dart';
  11. import 'package:photo_view/photo_view_gallery.dart';
  12. import '../../../resource/assets.gen.dart';
  13. import 'image_viewer_controller.dart';
  14. /// 图片预览页
  15. class ImageViewerPage extends BasePage<ImageViewerController> {
  16. const ImageViewerPage({super.key});
  17. /// 跳转
  18. /// [imageViewerItemList] 图片预览数据列表
  19. /// [index] 当前预览的索引,默认为0
  20. static void start(
  21. List<ImageViewerItem> imageViewerItemList, {
  22. int index = 0,
  23. }) {
  24. Map<String, dynamic> args = {
  25. AppPageArguments.imageViewerItemList: imageViewerItemList,
  26. AppPageArguments.index: index,
  27. };
  28. Get.toNamed(RoutePath.imageViewer, arguments: args);
  29. }
  30. @override
  31. backgroundColor() => ColorName.black;
  32. @override
  33. immersive() {
  34. // 沉浸式页面
  35. return true;
  36. }
  37. @override
  38. bool statusBarDarkFont() {
  39. // 状态栏,白色字体
  40. return false;
  41. }
  42. @override
  43. Widget buildBody(BuildContext context) {
  44. return Scaffold(
  45. backgroundColor: backgroundColor(),
  46. body: Stack(
  47. children: [
  48. // 预览图
  49. Obx(() {
  50. return PhotoViewGallery.builder(
  51. // 滚动特性
  52. scrollPhysics: const BouncingScrollPhysics(),
  53. // 页面数量
  54. itemCount: controller.imageViewerItemList.length,
  55. // 禁止旋转
  56. enableRotation: false,
  57. loadingBuilder:
  58. (context, event) => Center(
  59. child: SizedBox(
  60. width: 20.0,
  61. height: 20.0,
  62. child: CircularProgressIndicator(
  63. value:
  64. event == null
  65. ? 0
  66. : event.cumulativeBytesLoaded /
  67. (event.expectedTotalBytes ?? 0),
  68. ),
  69. ),
  70. ),
  71. onPageChanged: (index) {
  72. // 更新当前索引
  73. controller.updateCurrentIndex(index);
  74. },
  75. builder: (BuildContext context, int index) {
  76. return PhotoViewGalleryPageOptions.customChild(
  77. onTapDown: (context, details, controllerValue) {
  78. // 切换标题栏的显示和隐藏
  79. controller.toggleShowTitleBar();
  80. },
  81. minScale: PhotoViewComputedScale.contained,
  82. maxScale: PhotoViewComputedScale.covered * 2,
  83. initialScale: PhotoViewComputedScale.contained * 0.8,
  84. // 自定义视图
  85. child: _buildImageViewerItem(index),
  86. );
  87. },
  88. // backgroundDecoration: BoxDecoration(color: ColorName.black),
  89. pageController: controller.pageController,
  90. );
  91. }),
  92. // 指示器
  93. Visibility(
  94. visible: false,
  95. child: Positioned(
  96. left: 0,
  97. right: 0,
  98. bottom: 40.h,
  99. child: Obx(() {
  100. return _buildIndicator();
  101. }),
  102. ),
  103. ),
  104. // 标题栏
  105. Positioned(
  106. left: 0,
  107. top: 0,
  108. right: 0,
  109. child: Column(children: [_buildStatusBar(), _buildTitleBar()]),
  110. ),
  111. ],
  112. ),
  113. );
  114. }
  115. /// 构建每一项
  116. Widget _buildImageViewerItem(int index) {
  117. return Stack(
  118. fit: StackFit.expand,
  119. children: [
  120. Image(
  121. image: controller.getImageProvider(
  122. controller.imageViewerItemList[index],
  123. ),
  124. // fit: BoxFit.cover,
  125. ),
  126. ],
  127. );
  128. }
  129. /// 指示器
  130. Widget _buildIndicator() {
  131. return Center(
  132. child: Row(
  133. mainAxisSize: MainAxisSize.min,
  134. children: [
  135. Text(
  136. '${controller.currentIndex.value + 1}/${controller.imageViewerItemList.length}',
  137. style: TextStyle(
  138. color: Colors.white,
  139. fontSize: 18.sp,
  140. fontWeight: FontWeight.w500,
  141. ),
  142. ),
  143. ],
  144. ),
  145. );
  146. }
  147. /// 状态栏占位
  148. Widget _buildStatusBar() {
  149. double statusBarHeight = MediaQuery.of(Get.context!).padding.top;
  150. return Container(
  151. // 导航栏高度
  152. height: statusBarHeight,
  153. color: backgroundColor(),
  154. );
  155. }
  156. /// 标题栏
  157. Widget _buildTitleBar() {
  158. return Obx(() {
  159. return Visibility(
  160. visible: controller.isShowTitleBar.value,
  161. child: Container(
  162. height: kToolbarHeight,
  163. // 宽度,匹配父组件
  164. width: double.infinity,
  165. color: ColorName.black,
  166. padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 14.0),
  167. child: Stack(
  168. children: [
  169. // 返回按钮
  170. GestureDetector(
  171. onTap: controller.clickBack,
  172. child: Assets.images.iconImageViewerClose.image(
  173. width: 24.w,
  174. height: 24.h,
  175. ),
  176. ),
  177. // 标题
  178. Positioned(
  179. left: 0,
  180. top: 0,
  181. right: 0,
  182. child: Container(
  183. alignment: Alignment.center,
  184. child: Text(
  185. StringName.preview,
  186. style: TextStyle(
  187. fontSize: 16.sp,
  188. fontWeight: FontWeight.w500,
  189. color: ColorName.white,
  190. ),
  191. ),
  192. ),
  193. ),
  194. ],
  195. ),
  196. ),
  197. );
  198. });
  199. }
  200. }