flutter中自定義一個(gè)點(diǎn)擊圖片放大的widget

在開(kāi)發(fā)電商app的時(shí)候,用戶(hù)會(huì)需要點(diǎn)開(kāi)查看商品的大圖

此文章用到了第三方的package: photo_view,hero動(dòng)畫(huà) 可參考【Flutter實(shí)戰(zhàn)第二版】的介紹
主要涉及到兩個(gè)文件:animation_net_image.dartimage_browser.dart
animation_net_image.dart這個(gè)文件是自定義可點(diǎn)擊放大的圖片;
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;// 一定要保證和其他頁(yè)面不一樣
  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主要是我們自己對(duì)圖片的處理,你自己傳圖片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),
    );
  }
}

用的時(shí)候舉個(gè)例子:AnimationImageBuild(url, 88, 88, "appraisal" + state.model.code, BoxFit.fill);就可以了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容