基础库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

248 lines
7.4 KiB

  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:flutter/material.dart';
  4. import 'package:loading_indicator/loading_indicator.dart';
  5. import 'package:photo_view/photo_view.dart';
  6. import 'package:photo_view/photo_view_gallery.dart';
  7. import 'package:zhiying_comm/zhiying_comm.dart';
  8. ///图片预览控件
  9. class PhotoPreview extends StatefulWidget {
  10. List<PreviewImageData> previewImageDatas;
  11. int index;
  12. String heroTagSuffix;
  13. PhotoPreview({Key key, this.previewImageDatas, this.index = 0, this.heroTagSuffix = ""}) : super(key: key);
  14. PhotoPreview._showPhotoViewByData({Key key, this.previewImageDatas, this.index = 0, this.heroTagSuffix = ""}) : super(key: key) {}
  15. PhotoPreview._showPhotoViewByImages({Key key, List<String> images, this.index = 0, this.heroTagSuffix = ""}) : super(key: key) {
  16. if (images != null) {
  17. previewImageDatas = List();
  18. for (var img in images) {
  19. previewImageDatas.add(PreviewImageData(previewImageType: PreviewImageType.netUrl, data: img));
  20. }
  21. }
  22. }
  23. ///显示类型的一些预览
  24. static showPhotoPreview(BuildContext context, List<PreviewImageData> previewImageDatas, {int currentIndex = 0, String heroTagSuffix}) {
  25. Navigator.push(
  26. context,
  27. MaterialPageRoute(
  28. builder: (_) => PhotoPreview._showPhotoViewByData(
  29. previewImageDatas: previewImageDatas,
  30. index: currentIndex,
  31. heroTagSuffix: heroTagSuffix,
  32. )));
  33. }
  34. ///显示仅仅是一组list<String>类型的图片预览
  35. static showPhotoPreviewByimages(BuildContext context, List<String> images, {int currentIndex = 0, String heroTagSuffix = ""}) {
  36. Navigator.push(
  37. context,
  38. MaterialPageRoute(
  39. builder: (_) => PhotoPreview._showPhotoViewByImages(
  40. images: images,
  41. index: currentIndex,
  42. heroTagSuffix: heroTagSuffix,
  43. )));
  44. }
  45. @override
  46. _PhotoPreviewState createState() => _PhotoPreviewState();
  47. }
  48. class _PhotoPreviewState extends State<PhotoPreview> {
  49. @override
  50. void initState() {
  51. super.initState();
  52. }
  53. @override
  54. Widget build(BuildContext context) {
  55. return PhotoViewGalleryScreen(
  56. images: widget.previewImageDatas,
  57. index: widget.index,
  58. heroTagSuffix: widget.heroTagSuffix ?? "",
  59. );
  60. }
  61. @override
  62. void dispose() {
  63. super.dispose();
  64. }
  65. }
  66. ///图片预览数据
  67. class PreviewImageData {
  68. PreviewImageType previewImageType;
  69. String data;
  70. bool isSelect;
  71. String tag;
  72. PreviewImageData({this.previewImageType, this.data, this.isSelect = false, this.tag});
  73. }
  74. ///预览类型
  75. enum PreviewImageType {
  76. netUrl,
  77. ///网络图片
  78. filePath
  79. ///本地文件路径
  80. }
  81. class PhotoViewGalleryScreen extends StatefulWidget {
  82. List<PreviewImageData> images = [];
  83. int index = 0;
  84. String heroTagSuffix;
  85. PhotoViewGalleryScreen({Key key, @required this.images, this.index, this.heroTagSuffix}) : super(key: key);
  86. @override
  87. _PhotoViewGalleryScreenState createState() => _PhotoViewGalleryScreenState();
  88. }
  89. class _PhotoViewGalleryScreenState extends State<PhotoViewGalleryScreen> with AutomaticKeepAliveClientMixin {
  90. int currentIndex = 0;
  91. PageController pageController;
  92. PhotoViewScaleStateController scaleStateController;
  93. @override
  94. void initState() {
  95. scaleStateController = PhotoViewScaleStateController();
  96. // TODO: implement initState
  97. pageController = PageController(initialPage: widget?.index ?? 0);
  98. currentIndex = widget.index;
  99. super.initState();
  100. }
  101. @override
  102. void dispose() {
  103. scaleStateController.dispose();
  104. pageController.dispose();
  105. super.dispose();
  106. }
  107. @override
  108. Widget build(BuildContext context) {
  109. return Scaffold(
  110. backgroundColor: Colors.black,
  111. body: Stack(
  112. children: <Widget>[
  113. GestureDetector(
  114. onTap: () {
  115. Navigator.pop(context);
  116. },
  117. child: Container(
  118. margin: EdgeInsets.all(1),
  119. child: PhotoViewGallery.builder(
  120. scrollPhysics: const BouncingScrollPhysics(),
  121. builder: (BuildContext context, int index) {
  122. return PhotoViewGalleryPageOptions(
  123. scaleStateController: scaleStateController,
  124. imageProvider: _buildPage(context, index),
  125. heroAttributes: widget.heroTagSuffix.isNotEmpty ? PhotoViewHeroAttributes(tag: (widget.images[index].data ?? "") + widget.heroTagSuffix) : null,
  126. );
  127. },
  128. itemCount: widget.images.length,
  129. loadFailedChild: Container(
  130. child: Text("加载失败"),
  131. ),
  132. loadingBuilder: (context, event) {
  133. return Column(
  134. mainAxisAlignment: MainAxisAlignment.center,
  135. children: <Widget>[
  136. Container(
  137. width: 48,
  138. constraints: BoxConstraints(maxWidth: 48, maxHeight: 48),
  139. height: 48,
  140. child: LoadingIndicator(
  141. indicatorType: Indicator.ballSpinFadeLoader,
  142. color: Colors.white,
  143. )),
  144. ],
  145. );
  146. },
  147. backgroundDecoration: BoxDecoration(color: Colors.black),
  148. pageController: pageController,
  149. enableRotation: true,
  150. onPageChanged: (index) {
  151. setState(() {
  152. currentIndex = index;
  153. });
  154. },
  155. ),
  156. ),
  157. ),
  158. Positioned(
  159. //图片index显示
  160. top: MediaQuery.of(context).padding.top + 15,
  161. width: MediaQuery.of(context).size.width,
  162. child: Container(
  163. child: Center(
  164. child: Text("${currentIndex + 1}/${widget.images.length}", style: TextStyle(color: Colors.white, fontSize: 16)),
  165. ),
  166. ),
  167. ),
  168. Positioned(
  169. //右上角关闭按钮
  170. right: 10,
  171. top: MediaQuery.of(context).padding.top,
  172. child: IconButton(
  173. icon: Icon(
  174. Icons.close,
  175. size: 30,
  176. color: Colors.white,
  177. ),
  178. onPressed: () {
  179. Navigator.of(context).pop();
  180. },
  181. ),
  182. ),
  183. ],
  184. ),
  185. );
  186. }
  187. ImageProvider _buildPage(BuildContext context, int index) {
  188. var item = widget.images[index];
  189. if (item.previewImageType == PreviewImageType.netUrl) {
  190. return CachedNetworkImageProvider(item.data);
  191. } else if (item.previewImageType == PreviewImageType.filePath) {
  192. return Image.file(File(item.data)).image;
  193. }
  194. }
  195. @override
  196. // TODO: implement wantKeepAlive
  197. bool get wantKeepAlive => true;
  198. }
  199. class FadeRoute extends PageRouteBuilder {
  200. final Widget page;
  201. FadeRoute({this.page})
  202. : super(
  203. pageBuilder: (
  204. BuildContext context,
  205. Animation<double> animation,
  206. Animation<double> secondaryAnimation,
  207. ) =>
  208. page,
  209. transitionsBuilder: (
  210. BuildContext context,
  211. Animation<double> animation,
  212. Animation<double> secondaryAnimation,
  213. Widget child,
  214. ) =>
  215. FadeTransition(
  216. opacity: animation,
  217. child: child,
  218. ),
  219. );
  220. }