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.rhkb.cn/news/295268.html

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

相关文章

Java多线程实战-从零手搓一个简易线程池(三)线程工厂,核心线程与非核心线程逻辑实现

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️本系列源码仓库&#xff1a;多线程并发编程学习的多个代码片段(github) &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正…

漂亮哇塞的可视化大屏页面该如何设计?

要提升可视化界面的设计美观度&#xff0c;可以从以下几个方面入手&#xff1a; 使用高质量的图片和素材&#xff1a;使用高质量的图片和素材可以让界面更加美观。可以选择高清晰度的图片和素材&#xff0c;使得整个界面的质感更加高端。突出重点&#xff1a;在界面设计中&…

《QT实用小工具·八》数据库通用翻页类

1、概述 源码放在文章末尾 该项目实现数据库通用翻页类&#xff0c;主要包含如下功能&#xff1a; 1:自动按照设定的每页多少行数据分页 2:只需要传入表名/字段集合/每页行数/翻页指示按钮/文字指示标签 3:提供公共静态方法绑定字段数据到下拉框 4:建议条件字段用数字类型的主…

debian的使用笔记

1. XP风格任务栏 安装 debian-live-12.5.0-amd64-xfce.iso 后&#xff0c;把下面的任务栏删除&#xff0c;把上面的任务栏移到下面&#xff0c;然后设置如下选项 2. 命令自动补全 sudo apt install bash-completion 3. 找不到命令 sudo apt install command-not-found sudo…

RISC-V GNU Toolchain 工具链安装问题解决(含 stdio.h 问题解决)

我的安装过程主要参照 riscv-collab/riscv-gnu-toolchain 的官方 Readme 和这位佬的博客&#xff1a;RSIC-V工具链介绍及其安装教程 - 风正豪 &#xff08;大佬的博客写的非常详细&#xff0c;唯一不足就是 sudo make linux -jxx 是全部小写。&#xff09; 工具链前前后后我装了…

论文阅读RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection

文章目录 RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection问题笛卡尔坐标结构图Meta-Kernel Convolution RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection 论文&#xff1a;https://arxiv.org/pdf/2103.10039.pdf 代码&…

栈溢出攻击的软硬件缓解技术

为了防范栈溢出攻击&#xff0c;现代处理器架构&#xff08;如Arm架构&#xff09;具有执行权限。在Armv8-A中&#xff0c;主要的控制是在MMU地址转换表&#xff08;translation tables&#xff09;中的执行权限位。 UXN User (EL0) Execute-never …

SpringBoot+thymeleaf完成视频记忆播放功能

一、背景 1)客户要做一个视频播放功能,要求是系统能够记录观看人员在看视频时能够记录看到了哪个位置,在下次观看视频的时候能够从该位置进行播放。 2)同时,也要能够记录是谁看了视频,看了百分之多少。 说明:由于时间关系和篇幅原因,我们这里只先讨论第一个要求,第…

基于WEB的花卉养殖知识平台的设计与实现|SSM+ Mysql+Java(可运行源码+数据库+LW)植物绿植种植,留言管理,知识科普,新闻数据

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读300套最新项目持续更新中..... 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含ja…

Android Studio学习5——布局layout与视图view

wrap_content&#xff0c;内容有多大&#xff0c;就有多宽&#xff08;包裹&#xff09; 布局 padding 边框与它自身的内容 margin 控件与控件之间

docker容器环境安装记录(MAC M1)(完善中)

0、背景 在MAC M1中搭建商城项目环境时&#xff0c;采用docker统一管理开发工具&#xff0c;期间碰到了许多环境安装问题&#xff0c;做个总结。 1、安装redis 在宿主机新建redis.conf文件运行创建容器命令&#xff0c;进行容器创建、端口映射、文件挂载、以指定配置文件启动…

【Python面试题收录】Python的深浅拷贝

一、Python的深浅拷贝的区别 在Python中&#xff0c;深拷贝和浅拷贝是两种不同的对象复制机制&#xff0c;它们的主要区别在于如何处理对象内部所包含的可变或不可变类型的子对象。 浅拷贝 是指创建一个新的对象&#xff0c;但它只复制了原对象的第一层内容&#xff0c;也就是说…

Linux|centos7|postgresql数据库主从复制之异步还是同步的问题

前言&#xff1a; postgresql数据库是一个比较先进的中型关系型数据库&#xff0c;原本以为repmgr和基于repmgr的主从复制是挺简单的一个事情&#xff0c;但现实很快就给我教育了&#xff0c;原来postgresql和MySQL一样的&#xff0c;也是有异步或者同步的复制区别的 Postgre…

运放知识点总结

目录 一、运放基础知识 (operational amplifier) 1.由来 2.用途 3.符号 4.内部结构​编辑 5.虚短虚断 二、同相放大电路 &#xff08;Non-inverting Amplifier&#xff09; 三、反相放大电路 (Inverting Amplifier) 四、差分放大电路 (Difference Amplifier) 五、加法…

redis 数据库的安装及使用方法

目录 一 关系数据库与非关系型数据库 &#xff08;一&#xff09;关系型数据库 1&#xff0c;关系型数据库是什么 2&#xff0c;主流的关系型数据库有哪些 3&#xff0c;关系型数据库注意事项 &#xff08;二&#xff09;非关系型数据库 1&#xff0c;非关系型数据库是…

如果在 Ubuntu 系统中两个设备出现两个相同的端口号解决方案

问题描述&#xff1a; 自己的移动机器人在为激光雷达和IMU配置动态指定的端口时&#xff0c;发现激光雷达和深度相机配置的 idVendor 和 idProduct 相同&#xff0c;但是两个设备都具有不同的ttyUSB号&#xff0c;如下图所示 idVendor&#xff1a;代表着设备的生产商ID,由USB设…

EFK(elasticsearch+filebeat+kibana)日志分析平台搭建

本文是记录一下EFK日志平台的搭建过程 项目背景&#xff1a; 此次搭建的日志分析平台主要是采集服务器上的java服务的log日志(输出的日志已经是json格式)&#xff0c;这些日志都已经按照不同环境输出到/home/dev /home/test1 /home/test2 目录下了&#xff0c;按照不同的应…

Mybatis——一对一映射

一对一映射 预置条件 在某网络购物系统中&#xff0c;一个用户只能拥有一个购物车&#xff0c;用户与购物车的关系可以设计为一对一关系 数据库表结构&#xff08;唯一外键关联&#xff09; 创建两个实体类和映射接口 package org.example.demo;import lombok.Data;import …

在flutter中添加video_player【视频播放插件】

添加插件依赖 dependencies:video_player: ^2.8.3插件的用途 在Flutter框架中&#xff0c;video_player 插件是一个专门用于播放视频的插件。它允许开发者在Flutter应用中嵌入视频播放器&#xff0c;并提供了一系列功能来控制和定制视频播放体验。这个插件对于需要在应用中展…

舞蹈网站制作分享,舞蹈培训商城网站设计案例分享,wordpress主题分享

嘿&#xff0c;朋友们&#xff01;今天我要跟你们唠一唠一个超级酷炫的舞蹈培训商城网站设计案例。 咱先说说这个网站的目标哈&#xff0c;那就是得让喜欢舞蹈的小伙伴们能够轻轻松松找到自己心水的课程和商品。 那制作过程都有啥呢&#xff1f;别急&#xff0c;听我慢慢道来。…