Open perlatus opened 7 years ago
Heyho, I started working on it and it works when you are flinging down, but I think there is a problem with the small-box/big-box logic. I think I am still missing something and haven't understood everything properly. If you want to, take a look at it!
import 'package:flutter/material.dart';
import 'package:zoomable_image/zoomable_image.dart';
import '../common.dart';
const double _kMinFlingVelocity = 300.0;
class PhotoViewer extends StatefulWidget {
const PhotoViewer({Key key, this.imageURL}) : super(key: key);
final String imageURL;
@override
_PhotoViewerState createState() => new _PhotoViewerState(imageURL);
}
class _PhotoViewerState extends State<PhotoViewer> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _flingAnimation;
Offset _offset = Offset.zero;
double _scale = 1.0;
Offset _normalizedOffset;
double _previousScale;
final String _imageURL;
_PhotoViewerState(this._imageURL);
@override
void initState() {
super.initState();
_controller = new AnimationController(vsync: this)..addListener(_handleFlingAnimation);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
// The maximum offset value is 0,0. If the size of this renderer's box is w,h
// then the minimum offset value is w - _scale * w, h - _scale * h.
Offset _clampOffset(Offset offset) {
final Size size = context.size;
final Offset minOffset = new Offset(size.width, size.height) * (1.0 - _scale);
return new Offset(offset.dx.clamp(minOffset.dx, 0.0), offset.dy.clamp(minOffset.dy, 0.0));
}
void _handleFlingAnimation() {
setState(() {
_offset = _flingAnimation.value;
});
}
void _handleDoubleTap() {
//TODO: animate!
setState(() {
if (_scale > 1.0) {
_scale = 1.0;
_offset = Offset.zero;
} else {
_scale = 3.0;
_offset = _clampOffset(new Offset(context.size.width, context.size.height) / -2.0);
}
});
}
void _handleOnScaleStart(ScaleStartDetails details) {
setState(() {
_previousScale = _scale;
_normalizedOffset = (details.focalPoint - _offset) / _scale;
// The fling animation stops if an input gesture starts.
_controller.stop();
});
}
void _handleOnScaleUpdate(ScaleUpdateDetails details) {
setState(() {
_scale = (_previousScale * details.scale).clamp(1.0, 4.0);
// Ensure that image location under the focal point stays in the same place despite scaling.
_offset = _clampOffset(details.focalPoint - _normalizedOffset * _scale);
});
}
void _handleOnScaleEnd(ScaleEndDetails details) {
final double magnitude = details.velocity.pixelsPerSecond.distance;
if (magnitude < _kMinFlingVelocity) return;
final Offset direction = details.velocity.pixelsPerSecond / magnitude;
final double distance = (Offset.zero & context.size).shortestSide;
_flingAnimation =
new Tween<Offset>(begin: _offset, end: _clampOffset(_offset + direction * distance)).animate(_controller);
_controller
..value = 0.0
..fling(velocity: magnitude / 1000.0);
}
@override
Widget build(BuildContext context) {
Widget image = getProductImage(_imageURL);
return new ZoomableImage(new NetworkImage(_imageURL), scale: 16.0, backgroundColor: Colors.white);
// return new GestureDetector(
// //TODO: add proper double tab zoom in/zoom out
// onScaleStart: _handleOnScaleStart,
// onScaleUpdate: _handleOnScaleUpdate,
// onScaleEnd: _handleOnScaleEnd,
// onDoubleTap: _handleDoubleTap,
// child: new ClipRect(
// child: new Transform(
// transform: new Matrix4.identity()
// ..translate(_offset.dx, _offset.dy)
// ..scale(_scale),
// child: image,
// )));
}
}
No physics at the moment, so the moment your finger comes off the screen the image stops moving.