大家好,又见面了,我是你们的朋友全栈君。
/ Ios 、 Android 应用权限开启流程 /
IOS 应用 (询问权限、开启权限)
Android 应用(询问权限、开启权限)
/ 自定义选择相机和相册的对话框 /
创建一个存放对话框标题、相册拍照选项、关闭对话框的集合
代码语言:javascript复制[
{'label': '${titLab ?? '上传有效凭证'}'},
{'label': '拍照'},
{'label': '从手机相册选择'},
{'label': '取消'},
]
根据集合索引添加Widget
当索引 > 0 && < 集合长度 -1 , 添加对话框 拍照、选择相册 选项 ,同时添加分割线
当索引 == 0 , 添加对话框标题
当索引 == 集合长度 -1
代码语言:javascript复制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 里面进行配置
代码语言:javascript复制<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 命令加载依赖库
拍照、选择相册需要权限询问 , 判断是否开启相机或相册权限
代码语言:javascript复制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 函数里面完成权限初始化
代码语言:javascript复制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() 函数销毁权限
代码语言:javascript复制///权限关闭
void easyPerOff() {
if (_easyPermission != null) {
_easyPermission!.dispose();
}
}
IOS、Android 开启相机和相册权限步骤演示
代码语言:javascript复制
///选择相册 拍照
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;
}
});
}
IOS / 开启相机权限
IOS 开启相机权限
/ 拍照、选择相册图片终极目的上传到服务器 /
集成 dio、image_picker 插件
通过选择相册拍照实现图片上传到服务器
代码语言:javascript复制///添加图片并上传
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
代码语言:javascript复制 options = options ??
Options(
method: POST,
contentType: "multipart/form-data",
);
dio 实现文件上传
代码语言:javascript复制///上传文件
///
///[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("请求出错:$en$s");
if (errorCallback != null && e.type != DioErrorType.cancel) {
errorCallback(HttpError.dioError(e));
}
} catch (e, s) {
print("未知异常出错:$en$s");
if (errorCallback != null) {
errorCallback(HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!"));
}
}
}
创建模型层、Presenter、视图层 回调接口
代码语言:javascript复制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) 实现上传图片
代码语言:javascript复制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) 发起上传图片的请求
代码语言:javascript复制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)实现图片上传
代码语言:javascript复制selPhoCam(context, this, titLab: '上传图片资料',
iSelPicCallBack: (picFile) {
print('通过拍照或者选择相册获取多图片:$picFile');
presenter!.uploadPic(picFile);
});
main() 函数里面对网络请求管理类初始化
代码语言:javascript复制///网络请求管理初始化
HttpManager().init(baseUrl: '请求域名(baseUrl)');
图片上传成功
选择图片、拍照、上传 案例
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/190482.html原文链接:https://javaforall.cn