大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
/ Ios 、 Android 应用权限开启流程 /
IOS 应用 (询问权限、开启权限)
Android 应用(询问权限、开启权限)
/ 自定义选择相机和相册的对话框 /
创建一个存放对话框标题、相册拍照选项、关闭对话框的集合
[ {'label': '${titLab ?? '上传有效凭证'}'}, {'label': '拍照'}, {'label': '从手机相册选择'}, {'label': '取消'}, ]
根据集合索引添加Widget
当索引 > 0 && < 集合长度 -1 , 添加对话框 拍照、选择相册 选项 ,同时添加分割线
当索引 == 0 , 添加对话框标题
当索引 == 集合长度 -1
import 'package:flutter/material.dart'; import 'package:flutter_open_camera_photo/submsg/wx_text.dart'; Container addLine(BuildContext context) { ///添加线条 return Container( width: MediaQuery.of(context).size.width, height: 0.6, color: Color(0xffE6E8ED), ); } ///添加可点击选项 addSelOpt(BuildContext context, selOptCallBack, var diaDataItem, bgColor, fontColor, fontSize, height, borderRadius) { ///选项 return GestureDetector( onTap: () { ///关闭对话框 Navigator.pop(context); ///点击取消按钮 selOptCallBack(diaDataItem); }, child: selOpt(context, diaDataItem, bgColor, fontColor, fontSize, height, borderRadius), ); } selOpt(BuildContext context, var diaDataItem, bgColor, fontColor, fontSize, height, borderRadius) { return Container( width: MediaQuery.of(context).size.width, alignment: Alignment.center, height: height, decoration: BoxDecoration(color: Color(bgColor), borderRadius: borderRadius), child: commTextEll('${diaDataItem['label']}', 0xff1D1D1F, fontSize, FontWeight.normal, TextAlign.center), ); } commTextEll(_label, _color, _fontSize, _fontWeight, _textAlign, {isCenEll = true, maxLines = 1}) { return isCenEll ? WXText( breakWord(_label)!, textAlign: _textAlign, style: TextStyle( color: Color(_color), fontSize: _fontSize, fontWeight: _fontWeight), ) : Text( breakWord(_label)!, overflow: TextOverflow.ellipsis, textAlign: _textAlign, maxLines: maxLines, style: TextStyle( color: Color(_color), fontSize: _fontSize, fontWeight: _fontWeight), ); } ///overflow 属性省略号解决数字、长字母串整体显示省略号问题 String? breakWord(String? word) { if (word == null || word.isEmpty) { return word; } String breakWord = ' '; word.runes.forEach((element) { breakWord += String.fromCharCode(element); breakWord += '\u200B'; }); return breakWord; } void comBotDialog(BuildContext c, List<dynamic> diaData, selOptCallBack) { showModalBottomSheet( context: c, backgroundColor: Colors.transparent, builder: (BuildContext context) { ///列表视图集合 List<Widget> _diaChis = []; ///对话框文本数组大小 // ignore: unnecessary_null_comparison int diaDataL = (diaData == null) ? 0 : diaData.length; for (int i = 0; i < diaDataL; i++) { if (i > 0 && i < diaDataL - 1) { ///选项 _diaChis.add(addSelOpt(context, selOptCallBack, diaData[i], 0xffFFFFFF, 0xff1D1D1F, 18.0, 56.0, null)); ///添加线条 _diaChis.add(addLine(context)); } else { if (i == 0) { ///标题 _diaChis.add( selOpt( context, diaData[i], 0xffFFFFFF, 0xffB8BABF, 12.0, 32.0, BorderRadius.only( topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), ); ///添加线条 _diaChis.add(addLine(context)); } else { ///最后一项 _diaChis.add( Expanded( flex: 1, child: addSelOpt(context, selOptCallBack, diaData[i], 0xffF9FAFC, 0xff1D1D1F, 18.0, 72.0, null), ), ); } } } ///对话框 double _diaH = 32.0 + (diaDataL - 2) * 56.0 + (diaDataL - 2) * 0.6 + 72.0; return Container( width: double.infinity, ///对话框列表高度 height: _diaH, decoration: BoxDecoration( color: Color(0xffFFFFFF), borderRadius: BorderRadius.only( topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, ///列表视图集合 children: _diaChis, ), ); }); } ///选项点击事件 typedef void ISelOptCallBack(var sleOpt);
/ 集成flutter_easy_permission /
pubspec.yaml 添加依赖
Android 清单文件需要配置相机、相册、网络权限
IOS 需要在Xcode工具里面添加相机、相册权限说明 或 在info.list 里面进行配置
<key>NSCameraUsageDescription</key> <string>App需要您的同意,才能访问相机</string> <key>NSMicrophoneUsageDescription</key> <string>App需要您的同意,才能访问麦克风,用于拍照或者录制视频</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>App需要您的同意,才能访问相册</string> <key>NSPhotoLibraryUsageDescription</key> <string>App需要您的同意,才能访问相册</string>
Podfile 文件下配置相机和相册需要的库 , 然后执行 pod install 命令加载依赖库
拍照、选择相册需要权限询问 , 判断是否开启相机或相册权限
import 'package:flutter_easy_permission/constants.dart'; import 'package:flutter_easy_permission/flutter_easy_permission.dart'; ///申请相机+相册权限 Future<bool> requestCameraPermiss() async { //多个权限申请 const permissions = [ Permissions.CAMERA, ]; const permissionGroup = [PermissionGroup.Camera]; bool _hasPer = await FlutterEasyPermission.has( perms: permissions, permsGroup: permissionGroup); ///已经开启权限 if (_hasPer) { return true; } FlutterEasyPermission.request( perms: permissions, permsGroup: permissionGroup, rationale: "需要开启相机权限"); return false; } Future<bool> requestPhotoPermiss() async { //多个权限申请 const permissions = [ Permissions.WRITE_EXTERNAL_STORAGE, ]; const permissionGroup = [PermissionGroup.Photos]; bool _hasPer = await FlutterEasyPermission.has( perms: permissions, permsGroup: permissionGroup); ///已经开启权限 if (_hasPer) { return true; } FlutterEasyPermission.request( perms: permissions, permsGroup: permissionGroup, rationale: "需要开启相机权限"); return false; }
创建权限、拍照、选择相册(sel_pho_cam.dart )文件 , 用于初始化拍照、选择相册权限 , 实现拍照和选择相册功能 , 权限销毁 ,图片上传 .
initState 函数里面完成权限初始化
FlutterEasyPermission? _easyPermission; void fluPerCallBack( BuildContext context, ) { _easyPermission = FlutterEasyPermission() ..addPermissionCallback( onGranted: (requestCode, perms, perm) { print("Android Authorized:$perms"); print("iOS Authorized:$perm"); print("iOS Deny authorization_camera:$requestCode"); }, onDenied: (requestCode, perms, perm, isPermanent) { /*if (isPermanent) { FlutterEasyPermission.showAppSettingsDialog(title: "开启相机或者相册权限"); } else { print("Android Deny authorization:$perms"); print("iOS Deny authorization:$perm"); }*/ }, ); }
dispose() 函数销毁权限
///权限关闭 void easyPerOff() { if (_easyPermission != null) { _easyPermission!.dispose(); } }
IOS、Android 开启相机和相册权限步骤演示
///选择相册+拍照 void selPhoCam(BuildContext context, State state, {titLab, ISelPicCallBack? iSelPicCallBack}) { ///选择图片(相册+拍照) comBotDialog(context, [ {'label': '${titLab ?? '上传图片资料'}'}, {'label': '拍照'}, {'label': '从手机相册选择'}, {'label': '取消'}, ], (sleOpt) async { print('选项_$sleOpt'); var label = '${sleOpt['label']}'; switch (label) { case '拍照': bool _isHas = await requestCameraPermiss(); print('是否开启相机权限:$_isHas'); if (_isHas) { //_addPicUpLoad(context, ImageSource.camera, iSelPicCallBack); }else{ FlutterEasyPermission.showAppSettingsDialog(title: "开启相机或者相册权限"); } break; case '从手机相册选择': bool _isHas = await requestPhotoPermiss(); print('是否开启相册权限:$_isHas'); if (_isHas) { //_addPicUpLoad(context, ImageSource.gallery, iSelPicCallBack); }else{ FlutterEasyPermission.showAppSettingsDialog(title: "开启相机或者相册权限"); } break; } }); }
/ 拍照、选择相册图片终极目的上传到服务器 /
集成 dio、image_picker 插件
通过选择相册拍照实现图片上传到服务器
///添加图片并上传 void _addPicUpLoad(BuildContext context, ImageSource source, ISelPicCallBack? iSelPicCallBack) async { XFile? img = await ImagePicker().pickImage( source: source, maxWidth: MediaQuery.of(context).size.width, maxHeight: MediaQuery.of(context).size.height); if (img != null) { print("图片" + img.path); String picFilePath = img.path.replaceAll("File: ", "").replaceAll("'", ""); iSelPicCallBack!('$picFilePath'); } }
设置文件提交content-type
options = options ?? Options( method: POST, contentType: "multipart/form-data", );
dio 实现文件上传
///上传文件 /// ///[url] 网络请求地址不包含域名 ///[data] post 请求参数 ///[onSendProgress] 上传进度 ///[params] url请求参数支持restful ///[options] 请求配置 ///[successCallback] 请求成功回调 ///[errorCallback] 请求失败回调 ///[tag] 请求统一标识,用于取消网络请求 void upload({ required String? url, FormData? data, ProgressCallback? onSendProgress, Map<String, dynamic>? params, Options? options, HttpSuccessCallback? successCallback, HttpFailureCallback? errorCallback, @required String? tag, }) async { //检查网络是否连接 ConnectivityResult connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.none) { if (errorCallback != null) { errorCallback(HttpError(HttpError.NETWORK_ERROR, "网络异常,请稍后重试!")); } print("请求网络异常,请稍后重试!"); return; } //设置默认值 params = params ?? {}; //强制 POST 请求 options?.method = POST; options = options ?? Options( method: POST, contentType: "multipart/form-data", ); ///请求头 options.headers = await _headers(); try { CancelToken? cancelToken; if (tag != null) { cancelToken = _cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag]; _cancelTokens[tag] = cancelToken!; } Response response = await _client!.request(url!, onSendProgress: onSendProgress, data: data, queryParameters: params, options: options, cancelToken: cancelToken); var _responseData = response.data; return _responseData; /*int statusCode = _responseData["code"]; if (statusCode == 200) { //成功 successCallback!(_responseData["data"]); } else { //失败 String message = _responseData["msg"].toString(); errorCallback!(HttpError('$statusCode', message)); }*/ } on DioError catch (e, s) { print("请求出错:$e\n$s"); if (errorCallback != null && e.type != DioErrorType.cancel) { errorCallback(HttpError.dioError(e)); } } catch (e, s) { print("未知异常出错:$e\n$s"); if (errorCallback != null) { errorCallback(HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!")); } } }
创建模型层、Presenter、视图层 回调接口
import 'package:dio/dio.dart'; import 'package:flutter_open_camera_photo/base/model/IModel.dart'; import 'package:flutter_open_camera_photo/base/presenter/IPresenter.dart'; import 'package:flutter_open_camera_photo/base/view/IView.dart'; ///图片上传 abstract class CDataModel extends IModel { /// uploadPic(FormData formData, SuccessCallback s, FailureCallback f); } abstract class CDataPresenter extends IPresenter { ///上传图片 uploadPic(String file); } abstract class CDataView extends IView { /// uploadPic(d); }
模型层 (Model) 实现上传图片
import 'package:dio/dio.dart'; import 'package:flutter_open_camera_photo/base/http/http_manager.dart'; import 'package:flutter_open_camera_photo/base/model/AbstractModel.dart'; import 'package:flutter_open_camera_photo/busmer/mvp_callback.dart'; class MData extends AbstractModel implements CDataModel { @override void dispose() { // TODO: implement dispose HttpManager().cancel(tag!); } @override uploadPic(FormData data, s, f) async { return HttpManager().upload( url: '图片上传地址', tag: tag!, successCallback: (data) { s(data); }, errorCallback: (data) { f(data); }, data: data); } }
Presenter 创建 表单对象FormData 传递给模型层(Model) 发起上传图片的请求
import 'package:dio/dio.dart'; import 'package:flutter_open_camera_photo/base/model/IModel.dart'; import 'package:flutter_open_camera_photo/base/presenter/AbstractPresenter.dart'; import 'package:flutter_open_camera_photo/busmer/mvp_callback.dart'; import 'package:flutter_open_camera_photo/model/m_data.dart'; class PData extends AbstractPresenter<CDataView, CDataModel> implements CDataPresenter { @override IModel createModel() { return MData(); } @override uploadPic(String file) async { ///上传图片的文件名称 var name = file.substring(file.lastIndexOf("/") + 1, file.length); ///表单 FormData _formData = new FormData.fromMap({ 'file': await MultipartFile.fromFile( file, filename: name, ), }); view?.startLoading(); return model?.uploadPic(_formData, (data) { view?.showLoadSuccess(); view?.uploadPic(data); model?.dispose(); }, (error) { view?.showLoadFailure(error.code!, error.message!); }); } }
视图层(View)实现图片上传
selPhoCam(context, this, titLab: '上传图片资料', iSelPicCallBack: (picFile) { print('通过拍照或者选择相册获取多图片:$picFile'); presenter!.uploadPic(picFile); });
main() 函数里面对网络请求管理类初始化
///网络请求管理初始化 HttpManager().init(baseUrl: '请求域名(baseUrl)');
图片上传成功
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/190482.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...