Hibok
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

360 řádky
12 KiB

  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'dart:typed_data';
  4. import 'dart:ui';
  5. import 'package:cached_network_image/cached_network_image.dart';
  6. import 'package:chat/data/group_data_mgr.dart';
  7. import 'package:chat/models/group_info_model.dart';
  8. import 'package:chat/utils/screen.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:flutter/rendering.dart';
  11. import 'package:flutter/widgets.dart';
  12. import 'package:flutter_image_compress/flutter_image_compress.dart';
  13. import '../r.dart';
  14. import 'file_cache_mgr.dart';
  15. import 'group_member_model.dart';
  16. const ImgSizeLimit = 60 * 1024;
  17. /// Widget Util.
  18. class WidgetUtil {
  19. bool _hasMeasured = false;
  20. double _width;
  21. double _height;
  22. /// Widget rendering listener.
  23. /// Widget渲染监听.
  24. /// context: Widget context.
  25. /// isOnce: true,Continuous monitoring false,Listen only once.
  26. /// onCallBack: Widget Rect CallBack.
  27. void asyncPrepare(
  28. BuildContext context, bool isOnce, ValueChanged<Rect> onCallBack) {
  29. if (_hasMeasured) return;
  30. WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) {
  31. RenderBox box = context.findRenderObject();
  32. if (box != null && box.semanticBounds != null) {
  33. if (isOnce) _hasMeasured = true;
  34. double width = box.semanticBounds.width;
  35. double height = box.semanticBounds.height;
  36. if (_width != width || _height != height) {
  37. _width = width;
  38. _height = height;
  39. if (onCallBack != null) onCallBack(box.semanticBounds);
  40. }
  41. }
  42. });
  43. }
  44. /// Widget渲染监听.
  45. void asyncPrepares(bool isOnce, ValueChanged<Rect> onCallBack) {
  46. if (_hasMeasured) return;
  47. WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) {
  48. if (isOnce) _hasMeasured = true;
  49. if (onCallBack != null) onCallBack(null);
  50. });
  51. }
  52. ///get Widget Bounds (width, height, left, top, right, bottom and so on).Widgets must be rendered completely.
  53. ///获取widget Rect
  54. static Rect getWidgetBounds(BuildContext context) {
  55. RenderBox box = context.findRenderObject();
  56. return (box != null && box.semanticBounds != null)
  57. ? box.semanticBounds
  58. : Rect.zero;
  59. }
  60. static getCompressImg(String imgPath) async {
  61. var compressImg = await FlutterImageCompress.compressWithFile(imgPath,
  62. quality: 20, minWidth: Screen.width.toInt());
  63. print('图片压缩完毕 : ${compressImg.length}');
  64. if (compressImg.length > ImgSizeLimit) {
  65. //仍大于,再压缩一次
  66. compressImg = await FlutterImageCompress.compressWithFile(imgPath,
  67. quality: 20, minWidth: (Screen.width * 0.5).toInt());
  68. }
  69. return compressImg;
  70. }
  71. ///Get the coordinates of the widget on the screen.Widgets must be rendered completely.
  72. ///获取widget在屏幕上的坐标,widget必须渲染完成
  73. static Offset getWidgetLocalToGlobal(BuildContext context) {
  74. RenderBox box = context.findRenderObject();
  75. return box == null ? Offset.zero : box.localToGlobal(Offset.zero);
  76. }
  77. /// get image width height,load error return Rect.zero.(unit px)
  78. /// 获取图片宽高,加载错误情况返回 Rect.zero.(单位 px)
  79. /// image
  80. /// url network
  81. /// local url , package
  82. static Future<Rect> getImageWH(
  83. {Image image, String url, String localUrl, String package}) {
  84. if (image == null && url == null && localUrl == null) {
  85. return Future.value(Rect.zero);
  86. }
  87. Completer<Rect> completer = Completer<Rect>();
  88. Image img = image != null
  89. ? image
  90. : ((url != null && url.isNotEmpty)
  91. ? Image.network(url)
  92. : Image.asset(localUrl, package: package));
  93. img.image
  94. .resolve(new ImageConfiguration())
  95. .addListener(new ImageStreamListener(
  96. (ImageInfo info, bool _) {
  97. completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(),
  98. info.image.height.toDouble()));
  99. },
  100. onError: (dynamic exception, StackTrace stackTrace) {
  101. completer.completeError(exception, stackTrace);
  102. },
  103. ));
  104. return completer.future;
  105. }
  106. /// get image width height, load error throw exception.(unit px)
  107. /// 获取图片宽高,加载错误会抛出异常.(单位 px)
  108. /// image
  109. /// url network
  110. /// local url (full path/全路径,example:"assets/images/ali_connors.png",""assets/images/3.0x/ali_connors.png"" );
  111. /// package
  112. static Future<Rect> getImageWHE(
  113. {Image image, String url, String localUrl, String package}) {
  114. if (image == null && url == null && localUrl == null) {
  115. return Future.value(Rect.zero);
  116. }
  117. Completer<Rect> completer = Completer<Rect>();
  118. Image img = image != null
  119. ? image
  120. : ((url != null && url.isNotEmpty)
  121. ? Image.network(url)
  122. : Image.asset(localUrl, package: package));
  123. img.image
  124. .resolve(new ImageConfiguration())
  125. .addListener(new ImageStreamListener(
  126. (ImageInfo info, bool _) {
  127. completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(),
  128. info.image.height.toDouble()));
  129. },
  130. onError: (dynamic exception, StackTrace stackTrace) {
  131. completer.completeError(exception, stackTrace);
  132. },
  133. ));
  134. return completer.future;
  135. }
  136. static ImageProvider groupAvatar(String path ) {
  137. path = FileCacheMgr.replacePath(path);
  138. Uint8List fileData = File(path).readAsBytesSync();
  139. // print('fileData ${fileData.length}');
  140. return MemoryImage(fileData);
  141. }
  142. static Widget getAvatarNew(GroupInfoModel model,GlobalKey key,Function backPath) {
  143. List<GroupMemberModel> members =[];
  144. for(int k=0;k< model.members.length;k++){ //只加入存在群的
  145. GroupMemberModel mo = model.members[k];
  146. if(mo.inGroup==1){
  147. members.add(mo);
  148. }
  149. }
  150. if(model.image!=null && model.image.length>2){
  151. print('${model.name} 群头像地址:${model.image}');
  152. File file = new File(model.image);
  153. // int filelength = file.readAsBytesSync().length;
  154. // print('群头像地址file size : $filelength');
  155. if( file.existsSync()){ //防止头像文件被清除后
  156. Uint8List pngBytes =file.readAsBytesSync();
  157. print('pngBytes.lengthInBytes length;${pngBytes.lengthInBytes}');
  158. if(pngBytes.lengthInBytes>8000){
  159. return ClipRRect( borderRadius: BorderRadius.circular(5),child:Container(color: Color(0xffE9E9E9),width: 52,height: 52,child:
  160. Image.file(
  161. File(FileCacheMgr.replacePath(model.image)),
  162. fit: BoxFit.contain,
  163. width: 50,
  164. height: 50,
  165. ),) ,);
  166. }
  167. }else{
  168. backPath('');
  169. }
  170. }
  171. ///先让下面的图片显示,5秒后截图保存图片
  172. Future.delayed(Duration(seconds: 3),() async{
  173. // print('没有群图片-开始生成保存到本地:${model.members.length}');
  174. try {
  175. RenderRepaintBoundary boundary =
  176. key.currentContext.findRenderObject();
  177. var image = await boundary.toImage(pixelRatio:2);
  178. ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
  179. Uint8List pngBytes = byteData.buffer.asUint8List();
  180. File file =await FileCacheMgr().writeFile(model.sessionId.toString(),pngBytes);
  181. print('图片地址byteData${byteData.lengthInBytes}');
  182. if(byteData.lengthInBytes>8000 && members.length>1){ //图片保存成功
  183. GroupInfoMgr().updateAvatar(model.sessionId,file.path);
  184. backPath(file.path);
  185. }
  186. // ImageGallerySaver.saveImage(pngBytes);
  187. // return pngBytes;//这个对象就是图片数据
  188. } catch (e) {
  189. print(e);
  190. }
  191. });
  192. if(members.length>9){
  193. members = members.sublist(0,9);
  194. }
  195. if (members.length > 0) {
  196. double itemSize = 10;
  197. switch (members.length) {
  198. case 1:
  199. 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(
  200. imageUrl: members[0].avtar,
  201. width: 45,
  202. height: 45,
  203. placeholder: (context, url) =>
  204. Image.asset(R.assetsImagesDefaultNorAvatar,width: 45,
  205. height: 45,)
  206. ),),),),);
  207. break;
  208. case 2:
  209. return RepaintBoundary(key: key,child: ClipRRect(borderRadius: BorderRadius.circular(3),child: Container(color: Color(0xffE9E9E9),width: 52,height: 52,child: Row(children: <Widget>[
  210. Padding(padding: EdgeInsets.all(1),child: ClipRRect(
  211. borderRadius: BorderRadius.circular(3),
  212. child: CachedNetworkImage(
  213. imageUrl: members[0].avtar,
  214. width: 23,
  215. height: 23,
  216. placeholder: (context, url) =>
  217. Image.asset(R.assetsImagesDefaultNorAvatar, width: 23,
  218. height: 23,)
  219. ),
  220. ),),
  221. Padding(padding: EdgeInsets.all(1),child: ClipRRect(
  222. borderRadius: BorderRadius.circular(3),
  223. child: CachedNetworkImage(
  224. imageUrl: members[1].avtar,
  225. width: 23,
  226. height: 23,placeholder: (context, url) =>
  227. Image.asset(R.assetsImagesDefaultNorAvatar,width: 23,
  228. height: 23,)
  229. ),
  230. ),)
  231. ],),),),);
  232. case 3:
  233. return RepaintBoundary(key: key,child: ClipRRect(borderRadius: BorderRadius.circular(3),child: Container(color: Color(0xffE9E9E9),width: 52,height: 52,child: Column(children: <Widget>[
  234. Padding(padding: EdgeInsets.all(1),child: ClipRRect(
  235. borderRadius: BorderRadius.circular(3),
  236. child: CachedNetworkImage(
  237. imageUrl: members[0].avtar,
  238. width: 23,
  239. height: 23,placeholder: (context, url) =>
  240. Image.asset(R.assetsImagesDefaultNorAvatar,width: 23,
  241. height: 23,)
  242. ),
  243. ),),
  244. Row(children: <Widget>[
  245. Padding(padding: EdgeInsets.all(1),child: ClipRRect(
  246. borderRadius: BorderRadius.circular(3),
  247. child: CachedNetworkImage(
  248. imageUrl: members[1].avtar,
  249. width: 23,
  250. height: 23,placeholder: (context, url) =>
  251. Image.asset(R.assetsImagesDefaultNorAvatar,width: 23,
  252. height: 23,)
  253. ),
  254. ),),
  255. Padding(padding: EdgeInsets.all(1),child: ClipRRect(
  256. borderRadius: BorderRadius.circular(3),
  257. child: CachedNetworkImage(
  258. imageUrl: members[2].avtar,
  259. width: 23,
  260. height: 23,placeholder: (context, url) =>
  261. Image.asset(R.assetsImagesDefaultNorAvatar,width: 23,
  262. height: 23,)
  263. ),
  264. ),)
  265. ],)
  266. ],),),),);
  267. }
  268. if (members.length == 4) {
  269. itemSize = 23;
  270. } else {
  271. itemSize = 15;
  272. }
  273. List<Widget> widgetList = [];
  274. for (int k = 0; k < members.length; k++) {
  275. widgetList.add(Padding(padding: EdgeInsets.all(1),child: ClipRRect(
  276. borderRadius: BorderRadius.circular(3),
  277. child: CachedNetworkImage(
  278. imageUrl: members[k].avtar,
  279. width: itemSize,
  280. height: itemSize,placeholder: (context, url) =>
  281. Image.asset(R.assetsImagesDefaultNorAvatar,width: itemSize,
  282. height: itemSize,)
  283. ),
  284. ),));
  285. }
  286. return RepaintBoundary(key: key,child: ClipRRect(borderRadius: BorderRadius.circular(3),child: Container(
  287. color: Color(0xffE9E9E9),
  288. width: 52,
  289. height: 52,
  290. alignment: Alignment.center,
  291. child: Wrap(
  292. crossAxisAlignment: WrapCrossAlignment.start, children: widgetList),
  293. ),),);
  294. } else {
  295. return ClipRRect(borderRadius: BorderRadius.circular(3),child: Container(color: Color(0xffE9E9E9),),);
  296. }
  297. }
  298. }