Flutter玩转图片查看,速看立删

769 阅读2分钟

在手机APP中,点击图片查看也是一个必不可少的功能,比如图片放大、缩小,这篇文章将会带领你如何从简单的查看图片到封装查看图片的组件。文章使用Flutter结合第三方库photo_view进行演示

第三方插件地址:pub.dev/packages/ph…

首先需要安装该插件,在pubspec.yaml中引入

# 图片查看 https://pub.dev/packages/photo_view
photo_view: ^0.15.0

查看单张图片

单张图片查看比较简单,语法如下,注意要给外部容器设置宽高

Container(
  width: 600,
  height: 600,
  child: PhotoView(imageProvider: const AssetImage("images/img_1.png")),
)

效果如下

查看多张图片

多张图片需要使用到插件的Gallery实现

首先准备一个图片数组,方便等下演示多张图片的切换,这里是本地的存放的静态图片地址,如果是网络请求,可自行替换为图片网络地址即可

// 图片Url数组
List<String> imgUrlList = [];

@override
void initState() {
  // 遍历取出本地静态图片地址
  for (int i = 1; i <= 9; i++) {
    imgUrlList.add("images/img_${i}.png");
  }
  super.initState();
}

代码实现

Container(
  width: 600,
  height: 600,
  child: PhotoViewGallery.builder(
      // 图片个数
      itemCount: imgUrlList.length,
      builder: (BuildContext context, int index) {
        return PhotoViewGalleryPageOptions(
          imageProvider: AssetImage(imgUrlList[index]),
          // 设置图片初始加载的缩放比例
          initialScale: PhotoViewComputedScale.contained * 0.8,
          // 为图片创建平滑过渡
          heroAttributes: PhotoViewHeroAttributes(tag: imgUrlList[index]),
        );
      }),
)

封装Widget

那在尝试完查看单张或者多张图片后,我们可以在此基础进行二次封装,达到全局复用的效果,这样就可以减少我们在需要使用该功能的时候写重复性代码,话不多说,开干

首先,我们需要为图片创建一个结构类型,方便我们后续封装图片,我们可以通过为图片添加属性,丰富展示效果,例如下标:初始化显示图片,实现点击哪张图片就展示哪张标题:展示图片的信息

class ImgInfo {
  // 图片索引
  int? index;
  // 图片地址
  String? url;

  ImgInfo(int this.index, String this.url);
}

在布局页面中,先准备好图片数据,这里在本地市准备了9张图片,然后通过遍历依次取出,并封装为我们事先准备好的结构

// 图片数组
List<ImgInfo> imgUrlList = [];

@override
void initState() {
  // 遍历取出本地静态图片地址
  for (int i = 0; i < 9; i++) {
    String url = "images/img_${i + 1}.png";
    imgUrlList.add(ImgInfo(i, url));
  }
  super.initState();
}

开始布局,这里为了方便演示,只是进行了简单的布局,使用Wrap换行,为每个图片添加上下间隔

Wrap(
  spacing: 8.0,
  runSpacing: 8.0,
  children: imgUrlList.map((info) {
    // 获取屏幕的宽度,实现每张图片各占屏幕的一半
    double width = MediaQuery.of(context).size.width / 2;
    return GestureDetector(
      // 为图片添加点击事件,当点击图片会跳转到 查看图片 组件
      onTap: () {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (_) => PhotoPreView(
                      imgUrlList: imgUrlList,
                      defaultIndex: info.index!,
                    )));
      },
      child: Image.asset(info.url!,
          width: info.index! % 2 == 0 ? width : width - 8),
    );
  }).toList(),
)

布局效果如下

好,接下来就该到封装图片查看组件了

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

class PhotoPreView extends StatefulWidget {
  // 图片URL数组
  final List<ImgInfo> imgUrlList;
  // 默认显示图片的下标
  final int defaultIndex;
  //背景设计
  final BoxDecoration? decoration;
  const PhotoPreView({super.key, required this.imgUrlList, this.defaultIndex = 0, this.decoration});

  @override
  State<PhotoPreView> createState() => _PhotoPreViewState();
}

class _PhotoPreViewState extends State<PhotoPreView> {
  // 选中图片 下标
  late int selectImgIndex;
  // 控制器
  PageController? controller;
  // 标题文字
  late String title = "";
  // 图片总数
  int? length;

  @override
  void initState() {
    // 初始选中图片 位置
    selectImgIndex = widget.defaultIndex + 1;
    // 图片总数
    length = widget.imgUrlList.length;
    // 初始化显示的图片下标
    controller = PageController(initialPage: widget.defaultIndex);
    // 初始化标题
    title = "$selectImgIndex/$length";
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: PhotoViewGallery.builder(
        scrollPhysics: const BouncingScrollPhysics(),
        builder: (BuildContext context, int index) {
          return PhotoViewGalleryPageOptions(
            // 展示图:本地使用 AssetImage,网络使用 NetworkImage
            imageProvider: AssetImage(widget.imgUrlList[index].url ?? ""),
            // 图片 最小 缩放比例
            minScale: PhotoViewComputedScale.contained * 0.8,
            // 图片 最大 缩放比例
            maxScale: PhotoViewComputedScale.covered * 2.0,
            // 为图片切换创建平滑效果
            heroAttributes: PhotoViewHeroAttributes(tag: widget.imgUrlList[index].index ?? ""),
          );
        },
        // 图片个数
        itemCount: length,
        // 背景设计
        backgroundDecoration: widget.decoration,
        // 控制器
        pageController: controller,
        // 图片切换回调
        onPageChanged: (index) {
          // 更新选中图片的下标
          selectImgIndex = index + 1;
          // 更新标题
          title = "$selectImgIndex/$length";
          setState(() {});
        },
      ),
    );
  }
}

最终展示效果