/ 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; } }); } ?![]()
IOS / 開啟相機權限
![]()
IOS 開啟相機權限 ??
/ 拍照、選擇相冊圖片終極目的上傳到服務器 /
集成 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)');圖片上傳成功
選擇圖片、拍照、上傳 案例
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/403955.html
標籤:java
上一篇:Java集合面試題看這篇就夠了












