import 'dart:io'; import 'dart:typed_data'; import 'package:chat/chat/download_item.dart'; import 'package:chat/generated/i18n.dart'; import 'package:chat/models/ChatMsg.dart'; import 'package:flutter/material.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:oktoast/oktoast.dart'; import '../r.dart'; class PhotoPage extends StatefulWidget { final MsgModel msg; PhotoPage({this.msg}); @override _PhotoPageState createState() => _PhotoPageState(); } class _PhotoPageState extends State with SingleTickerProviderStateMixin { AnimationController _controller; Animation _animation; Offset _offset = Offset.zero; double _scale = 1.0; Offset _normalizedOffset; double _previousScale; double _kMinFlingVelocity = 600.0; ImageProvider provider; @override void initState() { super.initState(); getImgData(); _controller = AnimationController(vsync: this); _controller.addListener(() { setState(() { _offset = _animation.value; }); }); } getImgData() { if (widget.msg.localFile != null) { var fileData = File(widget.msg.localFile).readAsBytesSync(); provider = MemoryImage(fileData); } else { provider = MemoryImage(Uint8List.fromList(widget.msg.msgContent)); } } @override void dispose() { _controller.stop(); _controller.dispose(); super.dispose(); } Offset _clampOffset(Offset offset) { final Size size = context.size; // widget的屏幕宽度 final Offset minOffset = Offset(size.width, size.height) * (1.0 - _scale); // 限制他的最小尺寸 return Offset( offset.dx.clamp(minOffset.dx, 0.0), offset.dy.clamp(minOffset.dy, 0.0)); } void _handleOnScaleStart(ScaleStartDetails details) { setState(() { _previousScale = _scale; _normalizedOffset = (details.focalPoint - _offset) / _scale; // 计算图片放大后的位置 _controller.stop(); }); } void _handleOnScaleUpdate(ScaleUpdateDetails details) { setState(() { _scale = (_previousScale * details.scale).clamp(1.0, 3.0); // 限制放大倍数 1~3倍 _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; // 计算放大倍速,并相应的放大宽和高,比如原来是600*480的图片,放大后倍数为1.25倍时,宽和高是同时变化的 _animation = _controller.drive(Tween( begin: _offset, end: _clampOffset(_offset + direction * distance))); _controller ..value = 0.0 ..fling(velocity: magnitude / 1000.0); } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { Navigator.pop(context); }, onScaleStart: _handleOnScaleStart, onScaleUpdate: _handleOnScaleUpdate, onScaleEnd: _handleOnScaleEnd, child: Material( child: DownloadItem( msg: widget.msg, isAutoDown: false, onComplete: () { getImgData(); setState(() {}); }, child: Transform( transform: Matrix4.identity() ..translate(_offset.dx, _offset.dy) ..scale(_scale), child: Stack( children: [ Image( fit: BoxFit.fitWidth, image: provider ?? AssetImage(R.assetsImagesIcAlbum), ), Positioned( right: 10, bottom: 10, child: InkWell( onTap: saveToGallery, child: Container( padding: EdgeInsets.all(5), decoration: BoxDecoration( color: Colors.grey.withAlpha(150), borderRadius: BorderRadius.circular(8)), child: Icon(Icons.save_alt, color: Colors.white70), ))) ], )), )), ); } saveToGallery() async { if (widget.msg.localFile != null) { var data= File(widget.msg.localFile).readAsBytesSync(); ImageGallerySaver.saveImage(data).then((res) { print(res); if (res != null) { showToast(I18n.of(context).successfully_saved); } }); } else { ImageGallerySaver.saveImage(Uint8List.fromList(widget.msg.msgContent)) .then((res) { print(res); if (res != null) { showToast(I18n.of(context).successfully_saved); } }); } } }