Flutter开发之图片选择器

使用FLutter开发了一个图片选择的组件,功能如下:

1、支持设置最大可选图片的个数;
2、根据选择的图片个数自适应容器组件的高度;
3、可设置容器的最大高度;
4、支持点击放大和删除功能;

具体效果如下

请添加图片描述

使用到的三方插件:

get: ^4.6.6 #路由管理
flutter_easyloading: ^3.0.5 #加载动画、弹框
image_picker: ^1.0.4 #图片选择器
photo_view: ^0.14.0 #点击图片处理–放大,缩放、滑动

代码如下:

1、先添加相册、相机权限

iOS

	<key>NSCameraUsageDescription</key><string>更换个人头像需要使用相机功能</string><key>NSPhotoLibraryAddUsageDescription</key><string>更换个人头像需要使用相册功能</string><key>NSPhotoLibraryUsageDescription</key><string>更换个人头像需要使用相册功能</string>

Android

    <!-- 摄像头 --><uses-permission android:name="android.permission.CAMERA" /><!-- 文件读取 --><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/><!--    Android 13 READ_EXTERNAL_STORAGE权限需要使用READ_MEDIA_IMAGE、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO 来替代适配 --><uses-permission android:name="android.permission.READ_MEDIA_IMAGE" /><uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

2、创建一个ImagePickerMul的类

import 'dart:io';import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:photo_view/photo_view.dart';class ImagePickerMul extends StatefulWidget {final int maxCount; //最大选择图片数量final double maxHeight; //图片容器的最大高度final Function(List<XFile>) pickerImgCallBack; //选取图片成功之后拿到返回结果const ImagePickerMul({super.key,this.maxCount = 1000,this.maxHeight = 300.0,required this.pickerImgCallBack,});@overrideState<ImagePickerMul> createState() => _ImagePickerMulState();
}class _ImagePickerMulState extends State<ImagePickerMul> {final List<XFile> _imageFileList = []; //存放图片的数组final ImagePicker _picker = ImagePicker();dynamic _pickerImageError;int _bigImageIndex = 0; //存放需要放大的图片下标// 获取当前展示图的数量int getImageCount() {widget.pickerImgCallBack(_imageFileList);if (_imageFileList.length < widget.maxCount) {return _imageFileList.length + 1;} else {return _imageFileList.length;}}void _onImageButtonPressed(ImageSource source, {double? maxHeight,double? maxWidth,int? imageQuality,}) async {try {final pickedFileList = await _picker.pickMultipleMedia(maxHeight: maxHeight,maxWidth: maxWidth,imageQuality: imageQuality,);setState(() {if (_imageFileList.length < widget.maxCount) {if ((_imageFileList.length + pickedFileList.length) <=widget.maxCount) {//加上新选的不能超过总数量for (var element in pickedFileList) {_imageFileList.add(element);}} else {EasyLoading.showToast('最多只能选取${widget.maxCount}张图片,多余的图片将会自动删除!',duration: const Duration(milliseconds: 1500),);int avaliableCount = widget.maxCount - _imageFileList.length;for (int i = 0; i < avaliableCount; i++) {_imageFileList.add(pickedFileList[i]);}}}});} catch (e) {EasyLoading.showToast('$_pickerImageError');_pickerImageError = e;}}void _removeImage(int index) {setState(() {_imageFileList.removeAt(index);});}void _showBigImage(int index) {setState(() {_bigImageIndex = index;});//点击图片放大showDialog(context: context,builder: (context) {return Dialog(insetPadding: const EdgeInsets.only(left: 0.0),child: PhotoView(tightMode: true,imageProvider: FileImage(File(_imageFileList[_bigImageIndex].path,),),),);},);}Widget? displayBigImage() {if (_imageFileList.length > _bigImageIndex) {return Image.file(File(_imageFileList[_bigImageIndex].path,),fit: BoxFit.cover,);} else {return null;}}@overrideWidget build(BuildContext context) {int columnCount = 0;if (_imageFileList.length == widget.maxCount) {columnCount = (widget.maxCount / 3).ceil();} else {columnCount = ((_imageFileList.length + 1) / 3).ceil();}return _imageFileList.isNotEmpty? Container(height: columnCount * (Get.width / 3),constraints: BoxConstraints(maxHeight: widget.maxHeight,),child: GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,childAspectRatio: 1.0,),itemBuilder: (context, index) {if (_imageFileList.length < widget.maxCount) {if (index < _imageFileList.length) {return Padding(padding: const EdgeInsets.all(10.0),child: Stack(alignment: Alignment.center,children: [Positioned(top: 0.0,left: 0.0,bottom: 0.0,right: 0.0,child: GestureDetector(child: Image.file(File(_imageFileList[index].path,),fit: BoxFit.cover,),onTap: () => _showBigImage(index),),),Positioned(top: 0.0,right: 0.0,width: 20,height: 20,child: GestureDetector(child: const Icon(Icons.close,color: Colors.white,),onTap: () => _removeImage(index),),),],),);} else {//显示添加符号return Padding(padding: const EdgeInsets.all(10.0),child: IconButton(onPressed: () => _onImageButtonPressed(ImageSource.gallery,imageQuality: 40, //图片压缩),icon: const Icon(Icons.add_a_photo_outlined),),);}} else {//选满了return Container(padding: const EdgeInsets.all(10.0),child: Stack(alignment: Alignment.center,children: [Positioned(top: 0.0,left: 0.0,bottom: 0.0,right: 0.0,child: GestureDetector(child: Image.file(File(_imageFileList[index].path,),fit: BoxFit.cover,),onTap: () => _showBigImage(index),),),Positioned(top: 0.0,right: 0.0,width: 20,height: 20,child: GestureDetector(child: const SizedBox(child: Icon(Icons.close,color: Colors.white,),),onTap: () => _removeImage(index),),),],),);}},itemCount: getImageCount(),),): SizedBox(width: 90,height: 90,child: IconButton(onPressed: () => _onImageButtonPressed(ImageSource.gallery,imageQuality: 40, //图片压缩),icon: const Icon(Icons.add_a_photo_outlined),),);}
}

3、使用

body: Container(color: Colors.yellow,child: ImagePickerMul(maxCount: 9,maxHeight: 300.0,pickerImgCallBack: (imageList) {},),),

本人将会持续更新在开发过程中遇到的各种小demo,如果喜欢的话,欢迎给个star,ღ( ´・ᴗ・` )比心

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/797063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS4.0 ArkTS基本语法

一、项目目录结构 二、HelloWorld 当我们创建一个新的page时&#xff0c;IDE会给我们生成一个HelloWorld的模板 新建page 开启预览器 三、ArkTS基本组成 装饰器&#xff1a; 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。如上述示例中Entry、Component…

软考113-上午题-【计算机网络】-IPv6、无线网络、Windows命令

一、IPv6 IPv6 具有长达 128 位的地址空间&#xff0c;可以彻底解决 IPv4 地址不足的问题。由于 IPv4 地址是32 位二进制&#xff0c;所能表示的IP 地址个数为 2^32 4 294 967 29640 亿&#xff0c;因而在因特网上约有 40亿个P 地址。 由 32 位的IPv4 升级至 128 位的IPv6&am…

Qt快速入门到熟练(3.程序运行发布与设置图标)

程序运行发布 当我们执行过qt过后&#xff0c;将会在项目目录里面生成出一个debug构建目录&#xff0c;点击进去选择debug文件夹&#xff0c;就可以看到我们生成出来的可执行文件。 很显然我们的项目就叫做MyFirstWidget&#xff0c;所以生成的可执行文件在没有人为设置的情…

idea链接gitlab的token到期

报错 HTTP Request Request GET http://36.46.143.158:6060/api/v4/version failed wit

基于javaJSPssm实现的交通档案管理系统

开发语言&#xff1a;Java 框架&#xff1a;ssm 技术&#xff1a;JSP JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclip…

VM虚拟机部署code-server服务+tailscale内网穿透,实现随处coding

1.Linux下安装code-server Releases coder/code-server (github.com)https://github.com/coder/code-server/releases先去发布页面查看最新的code-server版本&#xff0c;下载命令示例&#xff1a; wget https://github.com/coder/code-server/releases/download/v4.22.1/co…

【操作系统】STM32-操作系统——持续更新

【操作系统】STM32-操作系统——持续更新 文章目录 前言一、ucosii二、freertos1.介绍2.移植 总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、ucosii UCOSII移植到STM32F103C8T6上之移植记录&#xff08;一&#xff09; UCOSII移植到ST…

物联网实战--入门篇之(九)安卓QT--开发框架

目录 一、QT简介 二、开发环境 三、编码风格 四、设计框架 五、总结 一、QT简介 QT是一款以C为基础的开发工具&#xff0c;已经包含了很多常用的库&#xff0c;除了基本的GUI以外&#xff0c;还有网络、数据库、多媒体、进程通信、串口、蓝牙等常用库&#xff0c;开发起来…

好看流光风格个人主页HTML源码

这是一款好看流光风格个人主页HTML源码&#xff0c;感觉挺喜欢的&#xff0c;需要的自行下载&#xff01; 源码下载 好看流光风格个人主页源码

SpringBoot3整合RabbitMQ之三_工作队列模型案例

SpringBoot3整合RabbitMQ之三_工作队列模型案例 文章目录 SpringBoot3整合RabbitMQ之三_工作队列模型案例2. 工作队列模型1. 消息发布者1. 创建工作队列的配置类2. 发布消费Controller 2. 消息消费者One3. 消息消费者Two4. 消息消费者Three5. 输出结果 2. 工作队列模型 1. 消息…

SGD随机梯度下降

一、补充概念&#xff1a; 目标函数&#xff08;Objective Function&#xff09;&#xff1a;这个术语通常指的是整个优化问题中需要最小化&#xff08;或最大化&#xff09;的函数。在机器学习和优化中&#xff0c;目标函数可以包括损失函数以及正则化项等。目标函数的最优化过…

怎么转换图片格式jpg?分享几种转换的方法

我们都知道现在图片格式种类非常多&#xff0c;比较常用的有jpg、png、webp等&#xff0c;很多时候&#xff0c;我们在网上保存的照片不是jpg格式的&#xff0c;查看或者编辑起来就很麻烦&#xff0c;这时候你可能需要将图片转换成jpg格式&#xff0c;那怎么转换图片格式jpg呢?…

【CNN】ConvMixer探究ViT的Patch Embedding: Patches Are All You Need?

Patches Are All You Need? 探究Patch Embedding在ViT上的作用&#xff0c;CNN是否可用该操作提升性能&#xff1f; 论文链接&#xff1a;https://openreview.net/pdf?idTVHS5Y4dNvM 代码链接&#xff1a;https://github.com/tmp-iclr/convmixer 1、摘要 ViT的性能是由于T…

我的 256天 创作纪念日

创作纪念日 我与CSDN的初识耕耘后的收获有笑有泪的日常小小的成就我的憧憬 我与CSDN的初识 在大一上学期的C语言课程中&#xff0c;我首次接触到CSDN。那时&#xff0c;面对众多难以理解的题目&#xff0c;我不得不频繁搜索相关知识和题解&#xff0c;CSDN成了我的救星。这个经…

这几个小众SaaS知识库工具原来这么好用,强烈推荐!

时代的进步和科技的发展&#xff0c;让我们有了更多高效的工作工具。由于云计算和SaaS&#xff08;Software as a Service&#xff09;的普及&#xff0c;越来越多的知识库工具被广大用户所知和使用。今天&#xff0c;就让我来为你推荐几款小众但卓效独特的SaaS知识库工具。 首…

市场首款!华邦电子发布内置PQC算法的闪存产品

3月27日&#xff0c;全球领先的半导体内存解决方案供应商华邦电子股份有限公司推出TrustME Secure Flash W77Q系列的最新扩展&#xff0c;包括256Mb、512Mb和1Gb器件。 这些突破性的安全闪存设备是市场上首款针对后量子密码学&#xff08;PQC&#xff09;实施Leighton-Micali签…

FSP7罗德与施瓦茨FSP7频谱分析仪

181/2461/8938产品概述&#xff1a; 罗德与施瓦茨 FSP7 频谱分析仪以其创新的测量和大量标准功能而著称。FSP7 没有提供多种选项&#xff0c;而是标配了最先进的频谱分析仪所需的所有功能和接口。FSP 具有如此丰富的功能&#xff0c;以极具吸引力的性价比提供最先进的频谱分析…

windows下Msys2编译OpenOCD方法与总结

windows下Msys2编译OpenOCD方法与总结 参考博客&#xff1a; 编译的总体方法&#xff1a;https://blog.csdn.net/MicroMehhh/article/details/135721360lib-usb库问题的解决办法&#xff1a;https://github.com/espressif/openocd-esp32/issues/162编译方法参考&#xff1a; …

智过网:一建继续教育,操作指南与周期解析

随着社会的快速发展和技术的不断更新&#xff0c;建筑行业对从业人员的专业素质要求也在逐步提高。为了确保一级建造师的专业技能能够与时俱进&#xff0c;满足行业发展的需求&#xff0c;继续教育成为了必不可少的环节。本文将详细解析一建继续教育的操作流程及其周期安排&…

前端开发学习笔记 3 (Chrome浏览器调试工具、Emmet语法、CSS复合选择器、CSS元素选择模式、CSS背景)

文章目录 Chrome浏览器调试工具Emmet语法CSS复合选择器后代选择器子选择器并集选择器伪类选择器 CSS元素选择模式元素选择模式概述CSS块标签CSS行内标签CSS行内块标签CSS元素显示模式转换 CSS背景CSS背景颜色CSS背景图片CSS背景图片平铺CSS背景图片位置CSS背景图片固定CSS背景复…