Flutter高仿微信系列共59篇,从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。
效果图:
实现代码:
//打开相册权限 void _openAblumPermission(int type) async { mediaType = type; bool isPhotosGranted = await Permission.photos.isGranted; bool isPhotosDenied = await Permission.photos.isDenied; if(isPhotosGranted){ _openAblum(); } else { if(isPhotosDenied){ _openAblum(); } else { //跳转到设置页面提示 _showPhotosConfirmationAlert(context); } } } // 为正常拍摄,请前往设备中的【设置】> 【隐私】> 【相机】中允许无他相机使用 _showPhotosConfirmationAlert(BuildContext context) { showPlatformDialog( context: context, builder: (_) => BasicDialogAlert( title: Text("无法使用相册"), content: Text("为编辑照片,请前往设备中的【设置】> 【隐私】> 【照片】中允许${AppManager.getInstance().appName}使用"), actions: <Widget>[ BasicDialogAction( title: Text("知道了"), onPressed: () { Navigator.pop(context); }, ), BasicDialogAction( title: Text("去设置"), onPressed: () { // 跳转到系统设置页 AppSettings.openAppSettings(); }, ), ], ), ); } void _openAblum() async{ LogUtils.d("打开相册 ${mediaType}"); List<AssetEntity> selectedAssets = []; List<AssetEntity>? imageList; if(mediaType == MEDIA_TYPE_PICTURE){ imageList = await AssetPicker.pickAssets(context,pickerConfig: AssetPickerConfig(maxAssets: 9,selectedAssets: selectedAssets,requestType: RequestType.image,),); } else if(mediaType == MEDIA_TYPE_VIDEO){ imageList = await AssetPicker.pickAssets(context,pickerConfig: AssetPickerConfig(maxAssets: 1,selectedAssets: selectedAssets,requestType: RequestType.video,),); } else { return; } LogUtils.d("打开相册 ${imageList}"); if(imageList == null){ return; } if(mediaType == MEDIA_TYPE_PICTURE){ List<String> imageResultList = []; for(int i = 0; i < imageList.length; i++){ AssetEntity ae = imageList[i]; File? file = await ae.file; String resultFilePath = file?.path??""; imageResultList.add(resultFilePath); } LogUtils.d("打开相册 _processPicture "); _processPicture(imageResultList); } else if(mediaType == MEDIA_TYPE_VIDEO){ //只有一个小视频 AssetEntity ae = imageList[0]; File? file = await ae.file; String resultFilePath = file?.path??""; _processVideo(resultFilePath); } } //处理图片 void _processPicture(List<String> imageResultList) async { LogUtils.d("处理图片选择file图片ae返回:${imageResultList}"); if(imageResultList == null){ return; } List<String> compressImageResultList = []; for(int i = 0; i < imageResultList.length; i++){ String resultFilePath = imageResultList[i]; LogUtils.d("压缩前图片:${resultFilePath}"); //压缩完成再发送 String compressImagePath = await CompressImageUtils.compressFile(fileName: resultFilePath); LogUtils.d("压缩后图片:${compressImagePath}"); compressImageResultList.add(compressImagePath); } String videoFilePath = ""; var result = await Navigator.push(context, MaterialPageRoute(builder: (context) => MomentsPublishWidget(type: CommonUtils.MOMENTS_TYPE_PICTURE, imageList: compressImageResultList, videoFilePath: videoFilePath,))); LogUtils.d("发布返回:${result}"); if(result != null && result){ _getData(); } } //处理小视频(相册、拍照) void _processVideo(String resultFilePath) async { LogUtils.d("选择file图片ae返回:${resultFilePath}"); if(resultFilePath == null || "" == resultFilePath){ return; } //最大100M的视频, 不是1024*1024*500 , 使用1000*100*500 int maxSize = 100000000; int fileSize = File(resultFilePath).lengthSync(); LogUtils.d("视频大小:${fileSize}"); if(fileSize > maxSize){ CommonToast.show(context, "上传视频大小不能超过100M", duration: 3); return ; } Navigator.push(context, MaterialPageRoute(builder: (context) => MomentsPublishWidget(type: CommonUtils.MOMENTS_TYPE_VIDEO, imageList: [], videoFilePath: resultFilePath,))); }