• 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


  • 相关阅读:
    Linux下zip命令使用
    docker镜像发布到阿里云镜像仓库
    基于官方镜像定制php-fpm容器
    docker-compose部署开发环境
    docker安装discuz!Q
    从零开始实现简单 RPC 框架 4:注册中心
    从零开始实现简单 RPC 框架 3:配置总线 URL
    从零开始实现简单 RPC 框架 2:扩展利器 SPI
    从零开始实现简单 RPC 框架 1:RPC 框架的结构和设计
    文本分类(六):pytorch实现DPCNN
  • 原文地址:https://www.cnblogs.com/ckAng/p/10649351.html
Copyright © 2020-2023  润新知