在手机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(() {});
},
),
);
}
}
最终展示效果