Created
May 6, 2021 08:50
-
-
Save Urkman/e765f5270c357f8f9d1f703d439d88c1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/cupertino.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:photo_view/photo_view.dart'; | |
// ignore: must_be_immutable | |
class HeroImageView extends StatelessWidget { | |
String urlString; | |
double height; | |
double width; | |
BoxFit fit; | |
Color dragBgColor; | |
String heroTag; | |
String test; | |
HeroImageView({this.urlString, this.width, this.height, this.fit, this.dragBgColor, this.heroTag}); | |
@override | |
Widget build(BuildContext context) { | |
return Center( | |
child: GestureDetector( | |
onTap: () { | |
Navigator.push( | |
context, | |
PageRouteBuilder( | |
opaque: true, | |
pageBuilder: (BuildContext context, _, __) { | |
return HeroPhotoViewRouteWrapper( | |
tag: heroTag ?? urlString, | |
imageProvider: NetworkImage( | |
urlString, | |
), | |
); | |
}, | |
transitionsBuilder: (___, Animation<double> animation, ____, Widget child) { | |
return FadeTransition( | |
opacity: animation, | |
child: child, | |
); | |
}, | |
), | |
); | |
}, | |
child: Container( | |
child: Hero( | |
tag: heroTag ?? urlString, | |
child: Image.network( | |
urlString, | |
height: height ?? MediaQuery.of(context).size.height, | |
width: width ?? MediaQuery.of(context).size.width, | |
fit: fit ?? BoxFit.cover, | |
// loadingBuilder: (_, child, chunk) => chunk != null ? Text("loading") : child, | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class HeroPhotoViewRouteWrapper extends StatelessWidget { | |
HeroPhotoViewRouteWrapper({this.imageProvider, this.tag, this.backgroundDecoration, this.minScale, this.maxScale, this.dragBgColor}); | |
final ImageProvider imageProvider; | |
final String tag; | |
final BoxDecoration backgroundDecoration; | |
final dynamic minScale; | |
final dynamic maxScale; | |
final Color dragBgColor; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
constraints: BoxConstraints.expand( | |
height: MediaQuery.of(context).size.height, | |
), | |
child: PhotoViewSwipe( | |
heroAttributes: PhotoViewHeroAttributes(tag: tag), | |
imageProvider: imageProvider, | |
dragBgColor: dragBgColor, | |
), | |
); | |
} | |
} | |
class PhotoViewSwipe extends StatefulWidget { | |
PhotoViewSwipe({ | |
Key key, | |
@required this.imageProvider, | |
this.dragBgColor, // default Colors.black.withOpacity(0.5) | |
this.dragDistance, // default 160 | |
// Standard photo_view | |
this.loadingBuilder, | |
this.loadFailedChild, | |
this.backgroundDecoration, | |
this.gaplessPlayback = false, | |
this.heroAttributes, | |
this.scaleStateChangedCallback, | |
this.enableRotation = false, | |
this.controller, | |
this.maxScale, | |
this.minScale, | |
this.initialScale, | |
this.basePosition, | |
this.scaleStateCycle, | |
this.onTapUp, | |
this.onTapDown, | |
this.customSize, | |
this.gestureDetectorBehavior, | |
this.tightMode, | |
this.filterQuality, | |
}) : child = null, | |
childSize = null, | |
super(key: key); | |
final ImageProvider imageProvider; | |
final Color dragBgColor; | |
final double dragDistance; | |
// Standard photo_view | |
final LoadingBuilder loadingBuilder; | |
final Widget loadFailedChild; | |
final Decoration backgroundDecoration; | |
final bool gaplessPlayback; | |
final PhotoViewHeroAttributes heroAttributes; | |
final Size customSize; | |
final ValueChanged<PhotoViewScaleState> scaleStateChangedCallback; | |
final bool enableRotation; | |
final Widget child; | |
final Size childSize; | |
final dynamic maxScale; | |
final dynamic minScale; | |
final dynamic initialScale; | |
final PhotoViewControllerBase controller; | |
final Alignment basePosition; | |
final ScaleStateCycle scaleStateCycle; | |
final PhotoViewImageTapUpCallback onTapUp; | |
final PhotoViewImageTapDownCallback onTapDown; | |
final HitTestBehavior gestureDetectorBehavior; | |
final bool tightMode; | |
final FilterQuality filterQuality; | |
@override | |
_PhotoViewSwipeState createState() => _PhotoViewSwipeState(); | |
} | |
class _PhotoViewSwipeState extends State<PhotoViewSwipe> { | |
Offset _position = Offset(0.0, 0.0); | |
bool _isZoomed = false; | |
PhotoViewScaleStateController scaleStateController; | |
@override | |
void initState() { | |
scaleStateController = PhotoViewScaleStateController(); | |
scaleStateController.outputScaleStateStream.listen((event) { | |
setState(() { | |
_isZoomed = event != PhotoViewScaleState.zoomedOut && event != PhotoViewScaleState.initial; | |
}); | |
}); | |
super.initState(); | |
} | |
@override | |
void dispose() { | |
scaleStateController?.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
backgroundColor: widget.dragBgColor ?? Colors.black.withOpacity(0.5), | |
body: Stack( | |
children: [ | |
Positioned( | |
left: _position.dx, | |
top: _position.dy, | |
child: GestureDetector( | |
onVerticalDragUpdate: !_isZoomed | |
? (details) { | |
setState(() => _position = Offset(0.0, _position.dy + details.delta.dy)); | |
} | |
: null, | |
onVerticalDragEnd: !_isZoomed | |
? (details) { | |
double pixelsPerSecond = _position.dy.abs(); | |
if (pixelsPerSecond > (widget.dragDistance ?? 160)) { | |
Navigator.pop(context); | |
} else { | |
setState(() => _position = Offset(0.0, 0.0)); | |
} | |
} | |
: null, | |
child: Container( | |
decoration: _position.dy == 0.0 ? (widget.backgroundDecoration ?? BoxDecoration(color: Colors.black)) : null, | |
height: MediaQuery.of(context).size.height, | |
width: MediaQuery.of(context).size.width, | |
child: PhotoView( | |
imageProvider: widget.imageProvider, | |
backgroundDecoration: BoxDecoration(color: Colors.transparent), | |
scaleStateController: scaleStateController, | |
loadingBuilder: widget.loadingBuilder, | |
gaplessPlayback: widget.gaplessPlayback, | |
heroAttributes: widget.heroAttributes, | |
scaleStateChangedCallback: widget.scaleStateChangedCallback, | |
enableRotation: widget.enableRotation, | |
controller: widget.controller, | |
maxScale: widget.maxScale, | |
minScale: widget.minScale, | |
initialScale: widget.initialScale, | |
basePosition: widget.basePosition, | |
scaleStateCycle: widget.scaleStateCycle, | |
onTapUp: widget.onTapUp, | |
onTapDown: widget.onTapDown, | |
customSize: widget.customSize, | |
gestureDetectorBehavior: widget.gestureDetectorBehavior, | |
tightMode: widget.tightMode, | |
filterQuality: widget.filterQuality, | |
), | |
), | |
), | |
), | |
], | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment