import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:chat/data/group_data_mgr.dart'; import 'package:chat/models/group_info_model.dart'; import 'package:chat/utils/screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; //import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:flutter_native_image/flutter_native_image.dart'; import '../r.dart'; import 'file_cache_mgr.dart'; import 'group_member_model.dart'; const ImgSizeLimit = 60 * 1024; /// Widget Util. class WidgetUtil { bool _hasMeasured = false; double _width; double _height; /// Widget rendering listener. /// Widget渲染监听. /// context: Widget context. /// isOnce: true,Continuous monitoring false,Listen only once. /// onCallBack: Widget Rect CallBack. void asyncPrepare( BuildContext context, bool isOnce, ValueChanged onCallBack) { if (_hasMeasured) return; WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { RenderBox box = context.findRenderObject(); if (box != null && box.semanticBounds != null) { if (isOnce) _hasMeasured = true; double width = box.semanticBounds.width; double height = box.semanticBounds.height; if (_width != width || _height != height) { _width = width; _height = height; if (onCallBack != null) onCallBack(box.semanticBounds); } } }); } /// Widget渲染监听. void asyncPrepares(bool isOnce, ValueChanged onCallBack) { if (_hasMeasured) return; WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { if (isOnce) _hasMeasured = true; if (onCallBack != null) onCallBack(null); }); } ///get Widget Bounds (width, height, left, top, right, bottom and so on).Widgets must be rendered completely. ///获取widget Rect static Rect getWidgetBounds(BuildContext context) { RenderBox box = context.findRenderObject(); return (box != null && box.semanticBounds != null) ? box.semanticBounds : Rect.zero; } static getCompressImg(String imgPath, {int quality = 20, int percentage = 20}) async { File compressedFile = await FlutterNativeImage.compressImage(imgPath, quality: quality, percentage: percentage); var k = compressedFile.readAsBytesSync().toList(); print('A图片压缩完毕 : ${k.length}'); // compressedFile. // var compressImg = await FlutterImageCompress.compressWithFile(imgPath, // quality: 20, minWidth: Screen.width.toInt()); // print('B图片压缩完毕 : ${compressImg.length}'); // if (compressImg.length > ImgSizeLimit) { // //仍大于,再压缩一次 // compressImg = await FlutterImageCompress.compressWithFile(imgPath, // quality: 20, minWidth: (Screen.width * 0.5).toInt()); // } return k; } ///Get the coordinates of the widget on the screen.Widgets must be rendered completely. ///获取widget在屏幕上的坐标,widget必须渲染完成 static Offset getWidgetLocalToGlobal(BuildContext context) { RenderBox box = context.findRenderObject(); return box == null ? Offset.zero : box.localToGlobal(Offset.zero); } /// get image width height,load error return Rect.zero.(unit px) /// 获取图片宽高,加载错误情况返回 Rect.zero.(单位 px) /// image /// url network /// local url , package static Future getImageWH( {Image image, String url, String localUrl, String package}) { if (image == null && url == null && localUrl == null) { return Future.value(Rect.zero); } Completer completer = Completer(); Image img = image != null ? image : ((url != null && url.isNotEmpty) ? Image.network(url) : Image.asset(localUrl, package: package)); img.image .resolve(new ImageConfiguration()) .addListener(new ImageStreamListener( (ImageInfo info, bool _) { completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(), info.image.height.toDouble())); }, onError: (dynamic exception, StackTrace stackTrace) { completer.completeError(exception, stackTrace); }, )); return completer.future; } /// get image width height, load error throw exception.(unit px) /// 获取图片宽高,加载错误会抛出异常.(单位 px) /// image /// url network /// local url (full path/全路径,example:"assets/images/ali_connors.png",""assets/images/3.0x/ali_connors.png"" ); /// package static Future getImageWHE( {Image image, String url, String localUrl, String package}) { if (image == null && url == null && localUrl == null) { return Future.value(Rect.zero); } Completer completer = Completer(); Image img = image != null ? image : ((url != null && url.isNotEmpty) ? Image.network(url) : Image.asset(localUrl, package: package)); img.image .resolve(new ImageConfiguration()) .addListener(new ImageStreamListener( (ImageInfo info, bool _) { completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(), info.image.height.toDouble())); }, onError: (dynamic exception, StackTrace stackTrace) { completer.completeError(exception, stackTrace); }, )); return completer.future; } static ImageProvider groupAvatar(String path) { path = FileCacheMgr.replacePath(path); Uint8List fileData = File(path).readAsBytesSync(); // print('fileData ${fileData.length}'); return MemoryImage(fileData); } static Widget getAvatarNew( GroupInfoModel model, GlobalKey key, Function backPath) { List members = []; for (int k = 0; k < model.members.length; k++) { //只加入存在群的 GroupMemberModel mo = model.members[k]; if (mo.inGroup == 1) { members.add(mo); } } if (model.image != null && model.image.length > 2) { print('${model.name} 群头像地址:${model.image}'); File file = new File(model.image); // int filelength = file.readAsBytesSync().length; // print('群头像地址file size : $filelength'); if (file.existsSync()) { //防止头像文件被清除后 Uint8List pngBytes = file.readAsBytesSync(); print('pngBytes.lengthInBytes length;${pngBytes.lengthInBytes}'); if (pngBytes.lengthInBytes > 8000) { return ClipRRect( borderRadius: BorderRadius.circular(5), child: Container( color: Color(0xffE9E9E9), width: 52, height: 52, child: Image.file( File(FileCacheMgr.replacePath(model.image)), fit: BoxFit.contain, width: 50, height: 50, ), ), ); } } else { backPath(''); } } ///先让下面的图片显示,5秒后截图保存图片 Future.delayed(Duration(seconds: 3), () async { // print('没有群图片-开始生成保存到本地:${model.members.length}'); try { RenderRepaintBoundary boundary = key.currentContext.findRenderObject(); var image = await boundary.toImage(pixelRatio: 2); ByteData byteData = await image.toByteData(format: ImageByteFormat.png); Uint8List pngBytes = byteData.buffer.asUint8List(); File file = await FileCacheMgr() .writeFile(model.sessionId.toString(), pngBytes); print('图片地址byteData${byteData.lengthInBytes}'); if (byteData.lengthInBytes > 8000 && members.length > 1) { //图片保存成功 GroupInfoMgr().updateAvatar(model.sessionId, file.path); backPath(file.path); } // ImageGallerySaver.saveImage(pngBytes); // return pngBytes;//这个对象就是图片数据 } catch (e) { print(e); } }); if (members.length > 9) { members = members.sublist(0, 9); } if (members.length > 0) { double itemSize = 10; switch (members.length) { case 1: return RepaintBoundary( key: key, child: ClipRRect( borderRadius: BorderRadius.circular(3), child: Container( color: Color(0xffE9E9E9), width: 52, height: 52, child: Padding( padding: EdgeInsets.all(1), child: CachedNetworkImage( imageUrl: members[0].avtar, width: 45, height: 45, placeholder: (context, url) => Image.asset( R.assetsImagesDefaultNorAvatar, width: 45, height: 45, )), ), ), ), ); break; case 2: return RepaintBoundary( key: key, child: ClipRRect( borderRadius: BorderRadius.circular(3), child: Container( color: Color(0xffE9E9E9), width: 52, height: 52, child: Row( children: [ Padding( padding: EdgeInsets.all(1), child: ClipRRect( borderRadius: BorderRadius.circular(3), child: CachedNetworkImage( imageUrl: members[0].avtar, width: 23, height: 23, placeholder: (context, url) => Image.asset( R.assetsImagesDefaultNorAvatar, width: 23, height: 23, )), ), ), Padding( padding: EdgeInsets.all(1), child: ClipRRect( borderRadius: BorderRadius.circular(3), child: CachedNetworkImage( imageUrl: members[1].avtar, width: 23, height: 23, placeholder: (context, url) => Image.asset( R.assetsImagesDefaultNorAvatar, width: 23, height: 23, )), ), ) ], ), ), ), ); case 3: return RepaintBoundary( key: key, child: ClipRRect( borderRadius: BorderRadius.circular(3), child: Container( color: Color(0xffE9E9E9), width: 52, height: 52, child: Column( children: [ Padding( padding: EdgeInsets.all(1), child: ClipRRect( borderRadius: BorderRadius.circular(3), child: CachedNetworkImage( imageUrl: members[0].avtar, width: 23, height: 23, placeholder: (context, url) => Image.asset( R.assetsImagesDefaultNorAvatar, width: 23, height: 23, )), ), ), Row( children: [ Padding( padding: EdgeInsets.all(1), child: ClipRRect( borderRadius: BorderRadius.circular(3), child: CachedNetworkImage( imageUrl: members[1].avtar, width: 23, height: 23, placeholder: (context, url) => Image.asset( R.assetsImagesDefaultNorAvatar, width: 23, height: 23, )), ), ), Padding( padding: EdgeInsets.all(1), child: ClipRRect( borderRadius: BorderRadius.circular(3), child: CachedNetworkImage( imageUrl: members[2].avtar, width: 23, height: 23, placeholder: (context, url) => Image.asset( R.assetsImagesDefaultNorAvatar, width: 23, height: 23, )), ), ) ], ) ], ), ), ), ); } if (members.length == 4) { itemSize = 23; } else { itemSize = 15; } List widgetList = []; for (int k = 0; k < members.length; k++) { widgetList.add(Padding( padding: EdgeInsets.all(1), child: ClipRRect( borderRadius: BorderRadius.circular(3), child: CachedNetworkImage( imageUrl: members[k].avtar, width: itemSize, height: itemSize, placeholder: (context, url) => Image.asset( R.assetsImagesDefaultNorAvatar, width: itemSize, height: itemSize, )), ), )); } return RepaintBoundary( key: key, child: ClipRRect( borderRadius: BorderRadius.circular(3), child: Container( color: Color(0xffE9E9E9), width: 52, height: 52, alignment: Alignment.center, child: Wrap( crossAxisAlignment: WrapCrossAlignment.start, children: widgetList), ), ), ); } else { return ClipRRect( borderRadius: BorderRadius.circular(3), child: Container( color: Color(0xffE9E9E9), ), ); } } }