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

flutter 动画双指放大图片的更多相关文章

  1. 通过uiview动画来放大图片

    UIImage *image=[UIImage imageNamed:"]; UIImageView *imageView=[[UIImageView alloc]init]; imageV ...

  2. 转:Flutter动画一

    1. 动画介绍 动画对于App来说,非常的重要.很多App,正是因为有了动画,所以才会觉得炫酷.移动端的动画库有非常的多,例如iOS上的Pop.web端的animate.css.Android端的An ...

  3. 在viewPager中双指缩放图片,双击缩放图片,单指拖拽图片

    我们就把这个问题叫做图片查看器吧,它的主要功能有: (项目地址:https://github.com/TZHANHONG/ImageViewer/releases/tag/1.0,里面的MyImage ...

  4. Flutter 动画详解(一)

    本文主要介绍了动画的原理相关概念,对其他平台的动画做了一个简要的梳理,并简要的介绍了Flutter动画的一些知识. 1. 动画介绍 动画对于App来说,非常的重要.很多App,正是因为有了动画,所以才 ...

  5. IOS下拉放大图片

    代码地址如下:http://www.demodashi.com/demo/11623.html 一.实现效果图 现在越来越多的APP中存在下拉放大图片的效果,今天贡献一下我的实现这种方法的原理,和我遇 ...

  6. jquery插件jquery.LightBox.js之点击放大图片并左右点击切换图片(仿相册插件)

    该插件乃本博客作者所写,目的在于提升作者的js能力,也给一些js菜鸟在使用插件时提供一些便利,老鸟就悠然地飞过吧. 此插件旨在实现目前较为流行的点击放大图片并左右点击切换图片的效果,您可以根据自己的实 ...

  7. Js_动画显示背景图片

    jAni是一个可以动画显示背景图片的jQuery插件.这个插件基本上是GIF动画的一个替代品,但是他有他的好处.所有浏览器都支持GIF形式的动画格式,而且也不需要额外的javaScript代码和标记. ...

  8. 微信浏览器返回刷新,监听微信浏览器返回事件,网页防复制,移动端禁止图片长按和vivo手机点击img标签放大图片

    以下代码都经过iphone7,华为MT7 ,谷歌浏览器,微信开发者工具,PC端微信验证.如有bug,还请在评论区留言. demo链接:https://pan.baidu.com/s/1c35mbjM ...

  9. 转:Flutter动画二

    1. 介绍 本文会从代码层面去介绍Flutter动画,因此不会涉及到Flutter动画的具体使用. 1.1 Animation库 Flutter的animation库只依赖两个库,Dart库以及phy ...

随机推荐

  1. pip自动生成和安装requirements.txt

    生成requirements.txt文件 pip freeze > requirements.txt 安装requirements.txt依赖 pip install -r requiremen ...

  2. SecureCRT 使用 rz命令提示waiting to receive.**B0100000023be50

    SecureCRT 远程连接Linux服务器,使用 rz命令提示waiting to receive.**B0100000023be50,或者使用sz命令提示: **B0100000023be50 解 ...

  3. hive并行执行作业; 强化在脑海的印象

    如果集群资源充足可以设置:set hive.exec.parallel=true; (默认是false) 这样相互独立的job可以并行执行!!!! count(distinct) 最好改写为group ...

  4. nodejs部署智能合约的方法-web3 0.20版本

    参考:https://www.jianshu.com/p/7e541cd67be2 部署智能合约的方法有很多,比如使用truffle框架,使用remix-ide等,在这里的部署方法是使用nodejs一 ...

  5. docker 10 docker的镜像原理

    镜像是什么? 镜像是一个轻量级,可执行的软件包,用来打包运行环境和基于运行环境开发的软件包,它包含某个软件运行环境的所有内容.包括代码,运行时的库,配置文件和环境变量 UnionFs(联合文件系统) ...

  6. express框架之跨域请求

    express.js跨域请求代码如下: app.all('*', function(req, res, next) { res.header("Access-Control-Allow-Or ...

  7. Linux如何查看端口状态

    netstat命令各个参数说明如下: -t : 指明显示TCP端口 -u : 指明显示UDP端口 -l : 仅显示监听套接字(所谓套接字就是使应用程序能够读写与收发通讯协议(protocol)与资料的 ...

  8. Error: Cannot find module 'babel-runtime/regenerator'

    在做调用阿里云短信接口时遇到的一个问题 错误原因:没有正确安装相应的mmodule 解决办法: 第一步:在package.json中加入依赖label-runtime 第二步:在Terminal中 n ...

  9. Python脱产8期 Day06 2019/4/18

    一 深浅拷贝 例:ls = [1, 'abc', [10]] 1.值拷贝:s1 = ls    # ls1直接将ls中存放的地址拿过来,>ls内部的值发生任何变化,ls1都会随之变化. 2.浅拷 ...

  10. linux内存源码分析 - 内存回收(整体流程)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 当linux系统内存压力就大时,就会对系统的每个压力大的zone进程内存回收,内存回收主要是针对匿名页和文 ...