Flutter圈子Flutter

flutter中自定义一个点击图片放大的widget

2021-11-19  本文已影响0人  小木虫666

在开发电商app的时候,用户会需要点开查看商品的大图

此文章用到了第三方的package: photo_view,hero动画 可参考【Flutter实战第二版】的介绍(https://book.flutterchina.club/chapter9/hero.html#自实现hero动画)
主要涉及到两个文件:animation_net_image.dartimage_browser.dart
animation_net_image.dart这个文件是自定义可点击放大的图片;
image_browser.dart主要是显示放大图片的浏览器

1.直接上代码(animation_net_image.dart)

import 'package:flutter/widgets.dart';
import 'package:yp_erp/Common/Util/image_url_format.dart';
import 'package:yp_erp/Common/Util/image_url_util.dart';
import 'package:yp_erp/Common/View/image_browser.dart';

class AnimationImageBuild extends StatefulWidget {
  final String heroTag;// 一定要保证和其他页面不一样
  final String imageURL; // 原图片url
  final BoxFit fit;
  final double width;
  final double height;

  const AnimationImageBuild(
    this.imageURL,
    this.width,
    this.height,
    this.heroTag,
    this.fit, {
    Key key,
  }) : super(key: key);

  @override
  _AnimationImageBuildState createState() => _AnimationImageBuildState();
}

class _AnimationImageBuildState extends State<AnimationImageBuild> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        showImageBrowser(
          context,
          0,
          [ImageUrlUtil.formatUrl(widget.imageURL)],
          heroTag: widget.heroTag + widget.imageURL,
        );
      },
      child: Hero(
        tag: widget.heroTag + widget.imageURL,
        child: Image.network(
          resizeImageUrlFill(
              widget.imageURL, widget.height.round(), widget.width.round()),
          height: widget.height,
          width: widget.width,
          fit: widget.fit,
        ),
      ),
    );
  }
}

resizeImageUrlFill和ImageUrlUtil.formatUr主要是我们自己对图片的处理,你自己传图片url即可

2.(image_browser.dart)文件

import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'package:photo_view/photo_view_gallery.dart';

void showImageBrowser(
  BuildContext context,
  final int index,
  List<String> imageURLs, {
  bool verticalGallery = false,
  Object heroTag = 0,
}) {
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => GalleryPhotoViewWrapper(
        imageURLs: imageURLs,
        backgroundDecoration: const BoxDecoration(
          color: Colors.black,
        ),
        heroTag: heroTag,
        initialIndex: index,
        scrollDirection: verticalGallery ? Axis.vertical : Axis.horizontal,
      ),
    ),
  );
}

class GalleryPhotoViewWrapper extends StatefulWidget {
  final LoadingBuilder loadingBuilder;
  final BoxDecoration backgroundDecoration;
  final dynamic minScale;
  final dynamic maxScale;
  final int initialIndex;
  final Object heroTag;
  final PageController pageController;
  final List<String> imageURLs;
  final Axis scrollDirection;

  GalleryPhotoViewWrapper({
    Key key,
    this.loadingBuilder,
    this.backgroundDecoration,
    this.minScale,
    this.maxScale,
    this.heroTag = 0,
    this.initialIndex = 0,
    @required this.imageURLs,
    this.scrollDirection = Axis.horizontal,
  })  : pageController = PageController(initialPage: initialIndex),
        super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _GalleryPhotoViewWrapperState();
  }
}

class _GalleryPhotoViewWrapperState extends State<GalleryPhotoViewWrapper> {
  int currentIndex = 0;

  void onPageChanged(int index) {
    setState(() {
      currentIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (currentIndex == 0) {
      currentIndex = widget.initialIndex;
    }

    return Scaffold(
      body: Container(
        decoration: widget.backgroundDecoration,
        constraints: BoxConstraints.expand(
          height: MediaQuery.of(context).size.height,
        ),
        child: InkWell(
          onTap: () {
            Navigator.pop(context);
          },
          child: Stack(
            alignment: Alignment.bottomCenter,
            children: <Widget>[
              PhotoViewGallery.builder(
                scrollPhysics: const BouncingScrollPhysics(),
                builder: _buildItem,
                itemCount: widget.imageURLs.length,
                loadingBuilder: widget.loadingBuilder,
                backgroundDecoration: widget.backgroundDecoration,
                pageController: widget.pageController,
                onPageChanged: onPageChanged,
                scrollDirection: widget.scrollDirection,
              ),
              Container(
                padding: const EdgeInsets.only(bottom: 20, left: 20, right: 20),
                child: Text(
                  " ${currentIndex + 1} / ${widget.imageURLs.length}",
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 17.0,
                    decoration: null,
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }

  PhotoViewGalleryPageOptions _buildItem(BuildContext context, int index) {
    final String item = widget.imageURLs[index];
    return PhotoViewGalleryPageOptions(
      imageProvider: NetworkImage(item),
      initialScale: PhotoViewComputedScale.contained,
      minScale: PhotoViewComputedScale.contained * (0.5 + index / 10),
      maxScale: PhotoViewComputedScale.covered * 4.1,
      heroAttributes: PhotoViewHeroAttributes(tag: widget.heroTag),
    );
  }
}

用的时候举个:AnimationImageBuild(url, 88, 88, "appraisal" + state.model.code, BoxFit.fill);就可以了

上一篇下一篇

猜你喜欢

热点阅读