|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
|
import 'package:photo_view/photo_view.dart';
|
|
|
|
|
import 'package:photo_view/photo_view_gallery.dart';
|
|
|
|
|
|
|
|
|
|
import 'cached_image_wrapper.dart';
|
|
|
|
|
|
|
|
|
|
// import 'package:image_gallery_saver/image_gallery_saver.dart';
|
|
|
|
|
|
|
|
|
|
class GalleryPhotoViewWrapper extends StatefulWidget {
|
|
|
|
|
GalleryPhotoViewWrapper({
|
|
|
|
|
this.loadingBuilder,
|
|
|
|
|
this.backgroundDecoration,
|
|
|
|
|
this.minScale,
|
|
|
|
|
this.maxScale,
|
|
|
|
|
this.initialIndex,
|
|
|
|
|
@required this.galleryItems,
|
|
|
|
|
this.scrollDirection = Axis.horizontal,
|
|
|
|
|
}) : pageController = PageController(initialPage: initialIndex);
|
|
|
|
|
|
|
|
|
|
final LoadingBuilder loadingBuilder;
|
|
|
|
|
final Decoration backgroundDecoration;
|
|
|
|
|
final dynamic minScale;
|
|
|
|
|
final dynamic maxScale;
|
|
|
|
|
final int initialIndex;
|
|
|
|
|
final PageController pageController;
|
|
|
|
|
final List galleryItems;
|
|
|
|
|
final Axis scrollDirection;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<StatefulWidget> createState() {
|
|
|
|
|
return _GalleryPhotoViewWrapperState();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _GalleryPhotoViewWrapperState extends State<GalleryPhotoViewWrapper> {
|
|
|
|
|
int currentIndex;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
currentIndex = widget.initialIndex;
|
|
|
|
|
super.initState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onPageChanged(int index) {
|
|
|
|
|
setState(() {
|
|
|
|
|
currentIndex = index;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Scaffold(
|
|
|
|
|
body: Container(
|
|
|
|
|
decoration: widget.backgroundDecoration,
|
|
|
|
|
constraints: BoxConstraints.expand(
|
|
|
|
|
height: MediaQuery.of(context).size.height,
|
|
|
|
|
),
|
|
|
|
|
child: Stack(
|
|
|
|
|
alignment: Alignment.bottomRight,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
PhotoViewGallery.builder(
|
|
|
|
|
scrollPhysics: const BouncingScrollPhysics(),
|
|
|
|
|
builder: _buildItem,
|
|
|
|
|
itemCount: widget.galleryItems.length,
|
|
|
|
|
loadingBuilder: widget.loadingBuilder,
|
|
|
|
|
backgroundDecoration: widget.backgroundDecoration,
|
|
|
|
|
pageController: widget.pageController,
|
|
|
|
|
onPageChanged: onPageChanged,
|
|
|
|
|
scrollDirection: widget.scrollDirection,
|
|
|
|
|
),
|
|
|
|
|
Positioned(
|
|
|
|
|
//图片index显示
|
|
|
|
|
top: MediaQuery.of(context).padding.top + 15,
|
|
|
|
|
width: MediaQuery.of(context).size.width,
|
|
|
|
|
child: Center(
|
|
|
|
|
child: Text("${currentIndex + 1}/${widget.galleryItems.length}",
|
|
|
|
|
style: TextStyle(color: Colors.white, fontSize: 16)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Positioned(
|
|
|
|
|
//右上角关闭按钮
|
|
|
|
|
right: 10,
|
|
|
|
|
top: MediaQuery.of(context).padding.top,
|
|
|
|
|
child: IconButton(
|
|
|
|
|
icon: Icon(
|
|
|
|
|
Icons.close,
|
|
|
|
|
size: 30,
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
),
|
|
|
|
|
onPressed: () {
|
|
|
|
|
Get.back();
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//动态申请权限,ios 要在info.plist 上面添加
|
|
|
|
|
Future<bool> requestPermission() async {
|
|
|
|
|
var status = await Permission.photos.status;
|
|
|
|
|
if (status.isDenied) {
|
|
|
|
|
await [Permission.photos].request();
|
|
|
|
|
}
|
|
|
|
|
return status.isGranted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PhotoViewGalleryPageOptions _buildItem(BuildContext context, int index) {
|
|
|
|
|
final GalleryExampleItem item = widget.galleryItems[index];
|
|
|
|
|
return PhotoViewGalleryPageOptions(
|
|
|
|
|
onTapUp: (BuildContext context, TapUpDetails details,
|
|
|
|
|
PhotoViewControllerValue controllerValue) {
|
|
|
|
|
Get.back();
|
|
|
|
|
},
|
|
|
|
|
imageProvider: NetworkImage(item.resource),
|
|
|
|
|
// initialScale: PhotoViewComputedScale.contained,
|
|
|
|
|
// minScale: PhotoViewComputedScale.contained * (0.5 + index / 10),
|
|
|
|
|
// maxScale: PhotoViewComputedScale.covered * 1.1,
|
|
|
|
|
|
|
|
|
|
heroAttributes: PhotoViewHeroAttributes(tag: item.id),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Hero 动画组件
|
|
|
|
|
// ignore: must_be_immutable
|
|
|
|
|
class GalleryExampleItemThumbnail extends StatelessWidget {
|
|
|
|
|
GalleryExampleItemThumbnail({Key key, this.galleryExampleItem, this.onTap})
|
|
|
|
|
: super(key: key);
|
|
|
|
|
|
|
|
|
|
final GalleryExampleItem galleryExampleItem;
|
|
|
|
|
|
|
|
|
|
final GestureTapCallback onTap;
|
|
|
|
|
UniqueKey uniqueKey = UniqueKey();
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
borderRadius: BorderRadius.circular(4),
|
|
|
|
|
),
|
|
|
|
|
child: GestureDetector(
|
|
|
|
|
onTap: onTap,
|
|
|
|
|
child: Hero(
|
|
|
|
|
tag: uniqueKey,
|
|
|
|
|
child: CachedImageWrapper(
|
|
|
|
|
url: galleryExampleItem.resource,
|
|
|
|
|
height: 15,
|
|
|
|
|
width: 15,
|
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//model
|
|
|
|
|
class GalleryExampleItem {
|
|
|
|
|
GalleryExampleItem({this.id, this.resource, this.isSvg = false});
|
|
|
|
|
//hero的id 不能重复
|
|
|
|
|
String id;
|
|
|
|
|
String resource;
|
|
|
|
|
bool isSvg;
|
|
|
|
|
}
|