flutter 动画双指放大图片

class GridAnimation extends StatefulWidget { @override State<StatefulWidget> createState() { return GridAnimationState(); } } class GridAnimationState extends State<GridAnimation> { List<String> lists = [ "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212557760&di=2c0ccc64ab23eb9baa5f6582e0e4f52d&imgtype=0&src=http%3A%2F%2Fpic.feizl.com%2Fupload%2Fallimg%2F170725%2F43998m3qcnyxwxck.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212557760&di=37d5107e6f7277bc4bfd323845a2ef32&imgtype=0&src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Fsmccloud%2Ffetch%2F2015%2F06%2F05%2F79697840747611479.JPEG", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212557760&di=95860b0fd501110885cf6e191f7403f0&imgtype=0&src=http%3A%2F%2Fuploads.5068.com%2Fallimg%2F1712%2F144-1G2011I420.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212636935&di=110a278fe4fb22f07d183a049f36cba3&imgtype=jpg&src=http%3A%2F%2Fimg2.imgtn.bdimg.com%2Fit%2Fu%3D3695896267%2C3833204074%26fm%3D214%26gp%3D0.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212557759&di=3730dccf46e4b4f35bcb882148b973ee&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fpic%2F3%2F71%2F4c5b0d26ad.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212557759&di=4f53fa8e1699def18e976deaee5558bf&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201707%2F07%2F20170707151851_r34Se.jpeg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212557758&di=ea77e663ac012b8ce7eb921454528cb8&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201707%2F07%2F20170707151853_Xr2UP.jpeg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686377&di=513a2deeb0b9f66ac9f7713c1f08e38c&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201809%2F20180926104109132.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686377&di=d895baef0710a780cbff871b68fbabba&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201810%2F20181015170515909.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686376&di=6c670e61692a4b8a8c97fc8d751df6e9&imgtype=0&src=http%3A%2F%2Fpic.qqtn.com%2Fup%2F2018-8%2F2018082209071335857.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686375&di=5772b73b9349682e9883d57394655c5e&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201809%2F20180926104109561.jpg", "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1919562808,974781852&fm=11&gp=0.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686375&di=6646871a196763dad8bfb7d0b74f4fad&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201809%2F20180925112416520.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686375&di=07280c585f18cac3c1f251e7a496e2f3&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201809%2F20180920095533914.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686374&di=e0d4e585e1bafcfc0534f793091fbd03&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201809%2F20180918142250630.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686374&di=734df4a0341928437473ffaf4103b04e&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201810%2F20181015170515157.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686374&di=da3b239ebf59f5baae05eea6c663e8e5&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201810%2F20181015111057142.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212686374&di=f1156ff86227ca20deeaf2251f9a4054&imgtype=0&src=http%3A%2F%2Fwmimg.sc115.com%2Fwm%2Fpic%2F1705%2F1705vzcqpmrsfxo.jpg", "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=509143600,2831498304&fm=26&gp=0.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212767984&di=79e2286d0ecd5a944183eb319af5a07e&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201809%2F20180920104457446.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212767983&di=779e1f58291cb90d7635fb7575c14149&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201810%2F20181015134233184.jpg", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542212833549&di=6f022bf302e786643fb43b9ba9c5a75e&imgtype=0&src=http%3A%2F%2Flife.southmoney.com%2Ftuwen%2FUploadFiles_6871%2F201809%2F20180926110752933.jpg" ]; void showPhoto(BuildContext context,f,index) { Navigator.push(context, MaterialPageRoute<void>( builder: (BuildContext context) { return Scaffold( appBar: AppBar( title: Text('图片${index+1}') ), body: SizedBox.expand( child: Hero( tag: index, child: new Photo(url:f), ), ), ); } )); } @override Widget build(BuildContext context) { return new Scaffold( appBar: AppBar( title: Text('GridAnimation'), ), body: new Column( children: <Widget>[ new Expanded( child: new SafeArea( top: false, bottom: false, child: new GridView.count( crossAxisCount: 2, mainAxisSpacing: 10.0, crossAxisSpacing: 4.0, padding: const EdgeInsets.all(4.0), childAspectRatio: 1.5, children: lists.map((f) { return new GestureDetector( onTap: () { var index; if(lists.contains(f)){ index = lists.indexOf(f); } showPhoto(context,f,index); }, child: Image.network(f,fit: BoxFit.cover,), ); }).toList(), ), ), ) ], )); } } class Photo extends StatefulWidget { const Photo({Key key, this.url}) : super(key: key); final url; @override State<StatefulWidget> createState() { return PhotoState(); } } class PhotoState extends State<Photo> with SingleTickerProviderStateMixin { AnimationController _controller; Animation<Offset> _animation; Offset _offset = Offset.zero; double _scale = 1.0; Offset _normalizedOffset; double _previousScale; double _kMinFlingVelocity = 600.0; @override void initState() { super.initState(); _controller = AnimationController(vsync: this); _controller.addListener(() { setState(() { _offset = _animation.value; }); }); } @override void dispose() { super.dispose(); _controller.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<Offset>( begin: _offset, end: _clampOffset(_offset + direction * distance))); _controller ..value = 0.0 ..fling(velocity: magnitude / 1000.0); } @override Widget build(BuildContext context) { return GestureDetector( onScaleStart: _handleOnScaleStart, onScaleUpdate: _handleOnScaleUpdate, onScaleEnd: _handleOnScaleEnd, child: ClipRect( child: Transform( transform: Matrix4.identity()..translate(_offset.dx, _offset.dy) ..scale(_scale), child: Image.network(widget.url,fit: BoxFit.cover,), ), // child: Image.network(widget.url,fit: BoxFit.cover,), ), ); } } 

 

 

效果:
 
image.png

 
image.png

 
image.png

说明:通过GestureDetector类的onScaleStart,onScaleUpdate,onScaleEnd方法,该方法会有一个回调,会将当前的位置返回回来,去计算图片的方法,
可以自己去设定图片的总大小,放大倍率等。应用了flutter的Animation




原文:https://www.jianshu.com/p/d66791effb68


转载于:https://www.cnblogs.com/ckAng/p/10649351.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值