Hibok
您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 
 
 
 

432 行
15 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:flutter/material.dart';
  9. import 'package:flutter/rendering.dart';
  10. import 'package:flutter/widgets.dart';
  11. //import 'package:flutter_image_compress/flutter_image_compress.dart';
  12. import 'package:flutter_native_image/flutter_native_image.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,
  61. {int quality = 20, int percentage = 20}) async {
  62. File compressedFile = await FlutterNativeImage.compressImage(imgPath,
  63. quality: quality, percentage: percentage);
  64. var k = compressedFile.readAsBytesSync().toList();
  65. print('A图片压缩完毕 : ${k.length}');
  66. // compressedFile.
  67. // var compressImg = await FlutterImageCompress.compressWithFile(imgPath,
  68. // quality: 20, minWidth: Screen.width.toInt());
  69. // print('B图片压缩完毕 : ${compressImg.length}');
  70. // if (compressImg.length > ImgSizeLimit) {
  71. // //仍大于,再压缩一次
  72. // compressImg = await FlutterImageCompress.compressWithFile(imgPath,
  73. // quality: 20, minWidth: (Screen.width * 0.5).toInt());
  74. // }
  75. return k;
  76. }
  77. ///Get the coordinates of the widget on the screen.Widgets must be rendered completely.
  78. ///获取widget在屏幕上的坐标,widget必须渲染完成
  79. static Offset getWidgetLocalToGlobal(BuildContext context) {
  80. RenderBox box = context.findRenderObject();
  81. return box == null ? Offset.zero : box.localToGlobal(Offset.zero);
  82. }
  83. /// get image width height,load error return Rect.zero.(unit px)
  84. /// 获取图片宽高,加载错误情况返回 Rect.zero.(单位 px)
  85. /// image
  86. /// url network
  87. /// local url , package
  88. static Future<Rect> getImageWH(
  89. {Image image, String url, String localUrl, String package}) {
  90. if (image == null && url == null && localUrl == null) {
  91. return Future.value(Rect.zero);
  92. }
  93. Completer<Rect> completer = Completer<Rect>();
  94. Image img = image != null
  95. ? image
  96. : ((url != null && url.isNotEmpty)
  97. ? Image.network(url)
  98. : Image.asset(localUrl, package: package));
  99. img.image
  100. .resolve(new ImageConfiguration())
  101. .addListener(new ImageStreamListener(
  102. (ImageInfo info, bool _) {
  103. completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(),
  104. info.image.height.toDouble()));
  105. },
  106. onError: (dynamic exception, StackTrace stackTrace) {
  107. completer.completeError(exception, stackTrace);
  108. },
  109. ));
  110. return completer.future;
  111. }
  112. /// get image width height, load error throw exception.(unit px)
  113. /// 获取图片宽高,加载错误会抛出异常.(单位 px)
  114. /// image
  115. /// url network
  116. /// local url (full path/全路径,example:"assets/images/ali_connors.png",""assets/images/3.0x/ali_connors.png"" );
  117. /// package
  118. static Future<Rect> getImageWHE(
  119. {Image image, String url, String localUrl, String package}) {
  120. if (image == null && url == null && localUrl == null) {
  121. return Future.value(Rect.zero);
  122. }
  123. Completer<Rect> completer = Completer<Rect>();
  124. Image img = image != null
  125. ? image
  126. : ((url != null && url.isNotEmpty)
  127. ? Image.network(url)
  128. : Image.asset(localUrl, package: package));
  129. img.image
  130. .resolve(new ImageConfiguration())
  131. .addListener(new ImageStreamListener(
  132. (ImageInfo info, bool _) {
  133. completer.complete(Rect.fromLTWH(0, 0, info.image.width.toDouble(),
  134. info.image.height.toDouble()));
  135. },
  136. onError: (dynamic exception, StackTrace stackTrace) {
  137. completer.completeError(exception, stackTrace);
  138. },
  139. ));
  140. return completer.future;
  141. }
  142. static ImageProvider groupAvatar(String path) {
  143. path = FileCacheMgr.replacePath(path);
  144. Uint8List fileData = File(path).readAsBytesSync();
  145. // print('fileData ${fileData.length}');
  146. return MemoryImage(fileData);
  147. }
  148. static Widget getAvatarNew(
  149. GroupInfoModel model, GlobalKey key, Function backPath) {
  150. List<GroupMemberModel> members = [];
  151. for (int k = 0; k < model.members.length; k++) {
  152. //只加入存在群的
  153. GroupMemberModel mo = model.members[k];
  154. if (mo.inGroup == 1) {
  155. members.add(mo);
  156. }
  157. }
  158. if (model.image != null && model.image.length > 2) {
  159. print('${model.name} 群头像地址:${model.image}');
  160. File file = new File(model.image);
  161. // int filelength = file.readAsBytesSync().length;
  162. // print('群头像地址file size : $filelength');
  163. if (file.existsSync()) {
  164. //防止头像文件被清除后
  165. Uint8List pngBytes = file.readAsBytesSync();
  166. // print('pngBytes.lengthInBytes length;${pngBytes.lengthInBytes}');
  167. if (pngBytes.lengthInBytes > 8000) {
  168. return ClipRRect(
  169. borderRadius: BorderRadius.circular(5),
  170. child: Container(
  171. color: Color(0xffE9E9E9),
  172. width: 52,
  173. height: 52,
  174. child: Image.file(
  175. File(FileCacheMgr.replacePath(model.image)),
  176. fit: BoxFit.contain,
  177. width: 50,
  178. height: 50,
  179. ),
  180. ),
  181. );
  182. }
  183. } else {
  184. backPath('');
  185. }
  186. }
  187. ///先让下面的图片显示,5秒后截图保存图片
  188. Future.delayed(Duration(seconds: 3), () async {
  189. // print('没有群图片-开始生成保存到本地:${model.members.length}');
  190. try {
  191. RenderRepaintBoundary boundary = key.currentContext.findRenderObject();
  192. var image = await boundary.toImage(pixelRatio: 2);
  193. ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
  194. Uint8List pngBytes = byteData.buffer.asUint8List();
  195. File file = await FileCacheMgr()
  196. .writeFile(model.sessionId.toString(), pngBytes);
  197. // print('图片地址byteData${byteData.lengthInBytes}');
  198. if (byteData.lengthInBytes > 8000 && members.length > 1) {
  199. //图片保存成功
  200. GroupInfoMgr().updateAvatar(model.sessionId, file.path);
  201. backPath(file.path);
  202. }
  203. // ImageGallerySaver.saveImage(pngBytes);
  204. // return pngBytes;//这个对象就是图片数据
  205. } catch (e) {
  206. print(e);
  207. }
  208. });
  209. if (members.length > 9) {
  210. members = members.sublist(0, 9);
  211. }
  212. if (members.length > 0) {
  213. double itemSize = 10;
  214. switch (members.length) {
  215. case 1:
  216. return RepaintBoundary(
  217. key: key,
  218. child: ClipRRect(
  219. borderRadius: BorderRadius.circular(3),
  220. child: Container(
  221. color: Color(0xffE9E9E9),
  222. width: 52,
  223. height: 52,
  224. child: Padding(
  225. padding: EdgeInsets.all(1),
  226. child: CachedNetworkImage(
  227. imageUrl: members[0].avtar,
  228. width: 45,
  229. height: 45,
  230. placeholder: (context, url) => Image.asset(
  231. R.assetsImagesDefaultNorAvatar,
  232. width: 45,
  233. height: 45,
  234. )),
  235. ),
  236. ),
  237. ),
  238. );
  239. break;
  240. case 2:
  241. return RepaintBoundary(
  242. key: key,
  243. child: ClipRRect(
  244. borderRadius: BorderRadius.circular(3),
  245. child: Container(
  246. color: Color(0xffE9E9E9),
  247. width: 52,
  248. height: 52,
  249. child: Row(
  250. children: <Widget>[
  251. Padding(
  252. padding: EdgeInsets.all(1),
  253. child: ClipRRect(
  254. borderRadius: BorderRadius.circular(3),
  255. child: CachedNetworkImage(
  256. imageUrl: members[0].avtar,
  257. width: 23,
  258. height: 23,
  259. placeholder: (context, url) => Image.asset(
  260. R.assetsImagesDefaultNorAvatar,
  261. width: 23,
  262. height: 23,
  263. )),
  264. ),
  265. ),
  266. Padding(
  267. padding: EdgeInsets.all(1),
  268. child: ClipRRect(
  269. borderRadius: BorderRadius.circular(3),
  270. child: CachedNetworkImage(
  271. imageUrl: members[1].avtar,
  272. width: 23,
  273. height: 23,
  274. placeholder: (context, url) => Image.asset(
  275. R.assetsImagesDefaultNorAvatar,
  276. width: 23,
  277. height: 23,
  278. )),
  279. ),
  280. )
  281. ],
  282. ),
  283. ),
  284. ),
  285. );
  286. case 3:
  287. return RepaintBoundary(
  288. key: key,
  289. child: ClipRRect(
  290. borderRadius: BorderRadius.circular(3),
  291. child: Container(
  292. color: Color(0xffE9E9E9),
  293. width: 52,
  294. height: 52,
  295. child: Column(
  296. children: <Widget>[
  297. Padding(
  298. padding: EdgeInsets.all(1),
  299. child: ClipRRect(
  300. borderRadius: BorderRadius.circular(3),
  301. child: CachedNetworkImage(
  302. imageUrl: members[0].avtar,
  303. width: 23,
  304. height: 23,
  305. placeholder: (context, url) => Image.asset(
  306. R.assetsImagesDefaultNorAvatar,
  307. width: 23,
  308. height: 23,
  309. )),
  310. ),
  311. ),
  312. Row(
  313. children: <Widget>[
  314. Padding(
  315. padding: EdgeInsets.all(1),
  316. child: ClipRRect(
  317. borderRadius: BorderRadius.circular(3),
  318. child: CachedNetworkImage(
  319. imageUrl: members[1].avtar,
  320. width: 23,
  321. height: 23,
  322. placeholder: (context, url) => Image.asset(
  323. R.assetsImagesDefaultNorAvatar,
  324. width: 23,
  325. height: 23,
  326. )),
  327. ),
  328. ),
  329. Padding(
  330. padding: EdgeInsets.all(1),
  331. child: ClipRRect(
  332. borderRadius: BorderRadius.circular(3),
  333. child: CachedNetworkImage(
  334. imageUrl: members[2].avtar,
  335. width: 23,
  336. height: 23,
  337. placeholder: (context, url) => Image.asset(
  338. R.assetsImagesDefaultNorAvatar,
  339. width: 23,
  340. height: 23,
  341. )),
  342. ),
  343. )
  344. ],
  345. )
  346. ],
  347. ),
  348. ),
  349. ),
  350. );
  351. }
  352. if (members.length == 4) {
  353. itemSize = 23;
  354. } else {
  355. itemSize = 15;
  356. }
  357. List<Widget> widgetList = [];
  358. for (int k = 0; k < members.length; k++) {
  359. widgetList.add(Padding(
  360. padding: EdgeInsets.all(1),
  361. child: ClipRRect(
  362. borderRadius: BorderRadius.circular(3),
  363. child: CachedNetworkImage(
  364. imageUrl: members[k].avtar,
  365. width: itemSize,
  366. height: itemSize,
  367. placeholder: (context, url) => Image.asset(
  368. R.assetsImagesDefaultNorAvatar,
  369. width: itemSize,
  370. height: itemSize,
  371. )),
  372. ),
  373. ));
  374. }
  375. return RepaintBoundary(
  376. key: key,
  377. child: ClipRRect(
  378. borderRadius: BorderRadius.circular(3),
  379. child: Container(
  380. color: Color(0xffE9E9E9),
  381. width: 52,
  382. height: 52,
  383. alignment: Alignment.center,
  384. child: Wrap(
  385. crossAxisAlignment: WrapCrossAlignment.start,
  386. children: widgetList),
  387. ),
  388. ),
  389. );
  390. } else {
  391. return ClipRRect(
  392. borderRadius: BorderRadius.circular(3),
  393. child: Container(
  394. color: Color(0xffE9E9E9),
  395. ),
  396. );
  397. }
  398. }
  399. }