YSTools.dart 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. import 'dart:isolate';
  2. import 'dart:math';
  3. import 'dart:ui';
  4. import 'package:flutter/cupertino.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:ysairplane/code/YSLogin.dart';
  7. import 'package:flutter_screenutil/screenutil.dart';
  8. import 'package:shared_preferences/shared_preferences.dart';
  9. import 'dart:math' as math;
  10. class YSDatePicker extends StatefulWidget {
  11. final ValueSetter<String> choose;
  12. const YSDatePicker({Key key, this.choose}) : super(key: key);
  13. @override
  14. _YSDatePickerState createState() => _YSDatePickerState();
  15. }
  16. class _YSDatePickerState extends State<YSDatePicker> {
  17. String birthday = DateTime.now().year.toString()+'-'+DateTime.now().month.toString().padLeft(2,'0')+'-'+DateTime.now().day.toString().padLeft(2,'0')+' '+
  18. DateTime.now().hour.toString().padLeft(2,'0')+':'+DateTime.now().minute.toString().padLeft(2,'0');
  19. @override
  20. Widget build(BuildContext context) {
  21. return Container(
  22. color: Colors.transparent,
  23. height: 280,
  24. child: Column(
  25. crossAxisAlignment: CrossAxisAlignment.end,
  26. children: [
  27. Container(
  28. height: 40,
  29. padding: EdgeInsets.only(left: wsp(40),right: wsp(40)),
  30. decoration: BoxDecoration(
  31. color: Colors.white,
  32. border: Border(bottom: BorderSide(width: 0.5,color: Color(0xFFEEEEEE)))
  33. ),
  34. child: Row(
  35. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  36. children: [
  37. GestureDetector(
  38. child: Text('取消',style: TextStyle(fontSize: zsp(30),color: Color(0xFF999999)),),
  39. onTap: (){
  40. Navigator.pop(context);
  41. },
  42. ),
  43. GestureDetector(
  44. child: Text('确定',style: TextStyle(fontSize: zsp(30),color: Color(0xFF108DE9)),),
  45. onTap: (){
  46. widget.choose(birthday);
  47. Navigator.pop(context);
  48. },
  49. )
  50. ],
  51. ),
  52. ),
  53. Container(
  54. height: 240,
  55. padding: EdgeInsets.all(10),
  56. decoration: BoxDecoration(
  57. color: Colors.white,
  58. borderRadius: BorderRadius.only(topLeft: Radius.circular(20),topRight: Radius.circular(20))
  59. ),
  60. child: CupertinoDatePicker(
  61. initialDateTime: DateTime.now(),
  62. onDateTimeChanged: (date) {
  63. birthday = date.year.toString()+'-'+date.month.toString().padLeft(2,'0')+'-'+date.day.toString().padLeft(2,'0')+' '+date.hour.toString().padLeft(2,'0')+':'+date.minute.toString().padLeft(2,'0');
  64. },
  65. //mode: CupertinoDatePickerMode.date,
  66. ),
  67. ),
  68. ],
  69. ),
  70. );
  71. }
  72. }
  73. class BottomInputDialog extends StatefulWidget {
  74. final Widget inputView;
  75. final double height;
  76. final Color color;
  77. const BottomInputDialog({Key key, this.inputView,this.height,this.color}) : super(key: key);
  78. @override
  79. _State createState() => _State();
  80. }
  81. class _State extends State<BottomInputDialog> with WidgetsBindingObserver{
  82. @override
  83. void initState() {
  84. WidgetsBinding.instance.addObserver(this);
  85. super.initState();
  86. }
  87. @override
  88. void didChangeMetrics() {
  89. WidgetsBinding.instance.addPostFrameCallback((_) {
  90. if(MediaQuery.of(context).viewInsets.bottom <= 0){
  91. Navigator.pop(context);
  92. if (!mounted) {
  93. return;
  94. }
  95. WidgetsBinding.instance.removeObserver(this);
  96. }
  97. });
  98. super.didChangeMetrics();
  99. }
  100. @override
  101. void dispose() {
  102. super.dispose();
  103. if (!mounted) {
  104. return;
  105. }
  106. WidgetsBinding.instance.removeObserver(this);
  107. }
  108. @override
  109. Widget build(BuildContext context) {
  110. return CupertinoPageScaffold(
  111. backgroundColor: Colors.transparent,
  112. child: Stack(
  113. children: <Widget>[
  114. GestureDetector(
  115. child: BackdropFilter(
  116. filter: ImageFilter.blur(sigmaX: 3, sigmaY: 3),
  117. child: Container(
  118. height: MediaQuery.of(context).size.height,
  119. color: widget.color!=null?widget.color:Colors.black12.withOpacity(0.8),
  120. ),
  121. ),
  122. onTap: () {
  123. Navigator.pop(context);
  124. if (!mounted) {
  125. return;
  126. }
  127. WidgetsBinding.instance.removeObserver(this);
  128. },
  129. ),
  130. Container(
  131. margin: EdgeInsets.only(top: MediaQuery.of(context).size.height-widget.height-MediaQuery.of(context).viewInsets.bottom),
  132. height: widget.height,
  133. decoration: BoxDecoration(
  134. color: Colors.white,
  135. borderRadius: BorderRadius.only(topLeft: Radius.circular(10),topRight: Radius.circular(10)),
  136. boxShadow: [
  137. BoxShadow(
  138. color: Colors.black12,
  139. offset: Offset(-1, -3),
  140. blurRadius: 5
  141. )
  142. ]
  143. ),
  144. padding: EdgeInsets.all(10),
  145. child: widget.inputView,
  146. )
  147. ],
  148. ),
  149. );
  150. }
  151. }
  152. class PopRoute extends PopupRoute{
  153. final Duration _duration = Duration(milliseconds: 300);
  154. Widget child;
  155. PopRoute({@required this.child});
  156. @override
  157. Color get barrierColor => null;
  158. @override
  159. bool get barrierDismissible => true;
  160. @override
  161. String get barrierLabel => null;
  162. @override
  163. Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
  164. return child;
  165. }
  166. @override
  167. Duration get transitionDuration => _duration;
  168. }
  169. wsp(int number){
  170. // return ScreenUtil().setWidth(number);
  171. return number*0.5;
  172. }
  173. hsp(int number){
  174. return number*0.5;
  175. //return ScreenUtil().setHeight(number);
  176. }
  177. zsp(int number){
  178. return number*0.5;
  179. //return ScreenUtil().setSp(number,allowFontScalingSelf: false);
  180. }
  181. isLogin(BuildContext context,{VoidCallback login}) async{
  182. SharedPreferences prefs = await SharedPreferences.getInstance();
  183. String token = prefs.getString('token');
  184. if(token==null){
  185. Navigator.of(context,rootNavigator: true).push(
  186. CupertinoPageRoute(
  187. builder: (context){
  188. return YSLogin();
  189. }
  190. )
  191. ).then((value){
  192. if(value!=null){
  193. login();
  194. }
  195. });
  196. }else{
  197. login();
  198. }
  199. }
  200. ///手机号验证
  201. bool isChinaPhoneLegal(String str) {
  202. return RegExp(r"^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$").hasMatch(str);
  203. }
  204. ///邮箱验证
  205. bool isEmail(String str) {
  206. return RegExp(r"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").hasMatch(str);
  207. }
  208. ///验证URL
  209. bool isUrl(String value) {
  210. return RegExp(r"^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+").hasMatch(value);
  211. }
  212. ///验证身份证
  213. bool isIdCard(String value) {
  214. return RegExp(r"\d{17}[\d|x]|\d{15}").hasMatch(value);
  215. }
  216. ///验证中文
  217. bool isChinese(String value) {
  218. return RegExp(r"[\u4e00-\u9fa5]").hasMatch(value);
  219. }
  220. class LogUtil {
  221. static var _separator = "=";
  222. static var _split =
  223. "$_separator$_separator$_separator$_separator$_separator$_separator$_separator$_separator$_separator";
  224. static var _title = "Yl-Log";
  225. static var _isDebug = true;
  226. static int _limitLength = 800;
  227. static String _startLine = "$_split$_title$_split";
  228. static String _endLine = "$_split$_separator$_separator$_separator$_split";
  229. static void init({String title, @required bool isDebug,int limitLength}) {
  230. _title = title;
  231. _isDebug = isDebug;
  232. _limitLength = limitLength??=_limitLength;
  233. _startLine = "$_split$_title$_split";
  234. var endLineStr = StringBuffer();
  235. var cnCharReg = RegExp("[\u4e00-\u9fa5]");
  236. for (int i = 0; i < _startLine.length; i++) {
  237. if (cnCharReg.stringMatch(_startLine[i]) != null) {
  238. endLineStr.write(_separator);
  239. }
  240. endLineStr.write(_separator);
  241. }
  242. _endLine = endLineStr.toString();
  243. }
  244. //仅Debug模式可见
  245. static void d(dynamic obj) {
  246. if (_isDebug) {
  247. _log(obj.toString());
  248. }
  249. }
  250. static void v(dynamic obj) {
  251. _log(obj.toString());
  252. }
  253. static void _log(String msg) {
  254. print("$_startLine");
  255. _logEmpyLine();
  256. if(msg.length<_limitLength){
  257. print(msg);
  258. }else{
  259. segmentationLog(msg);
  260. }
  261. _logEmpyLine();
  262. print("$_endLine");
  263. }
  264. static void segmentationLog(String msg) {
  265. var outStr = StringBuffer();
  266. for (var index = 0; index < msg.length; index++) {
  267. outStr.write(msg[index]);
  268. if (index % _limitLength == 0 && index!=0) {
  269. print(outStr);
  270. outStr.clear();
  271. var lastIndex = index+1;
  272. if(msg.length-lastIndex<_limitLength){
  273. var remainderStr = msg.substring(lastIndex,msg.length);
  274. print(remainderStr);
  275. break;
  276. }
  277. }
  278. }
  279. }
  280. static void _logEmpyLine(){
  281. print("");
  282. }
  283. }
  284. //indicate
  285. Widget indicateString(String longStr,String str,String otherStr){
  286. List strings = longStr.split(str);
  287. print(strings);
  288. return Container(
  289. child: RichText(
  290. text: longStr!=str?TextSpan(
  291. children:
  292. [
  293. for(int i = 0;i<strings.length;i++)TextSpan(
  294. children: [
  295. TextSpan(
  296. text: strings[i]==''?str:strings[i],
  297. style: TextStyle(fontSize: zsp(32),color: strings[i]==''?Color(0xFF007AFF):Color(0xFF444444)),
  298. ),
  299. ]
  300. ),
  301. TextSpan(
  302. text: ' $otherStr',
  303. style: TextStyle(fontSize: zsp(26),color: Color(0xFF999999)),
  304. )
  305. ]
  306. ):TextSpan(
  307. children:[
  308. TextSpan(
  309. text: longStr,
  310. style: TextStyle(fontSize: zsp(32),color: Color(0xFF007AFF)),
  311. ),
  312. TextSpan(
  313. text: ' $otherStr',
  314. style: TextStyle(fontSize: zsp(26),color: Color(0xFF999999)),
  315. )
  316. ]
  317. ),
  318. ),
  319. );
  320. }
  321. class ExpandableText extends StatefulWidget {
  322. final String text;
  323. final int maxLines;
  324. final TextStyle style;
  325. final bool expand;
  326. const ExpandableText({Key key, this.text, this.maxLines, this.style, this.expand}) : super(key: key);
  327. @override
  328. State<StatefulWidget> createState() {
  329. return _ExpandableTextState(text, maxLines, style, expand);
  330. }
  331. }
  332. class _ExpandableTextState extends State<ExpandableText> {
  333. final String text;
  334. final int maxLines;
  335. final TextStyle style;
  336. bool expand;
  337. _ExpandableTextState(this.text, this.maxLines, this.style, this.expand) {
  338. if (expand == null) {
  339. expand = false;
  340. }
  341. }
  342. @override
  343. Widget build(BuildContext context) {
  344. return LayoutBuilder(builder: (context, size) {
  345. final span = TextSpan(text: text ?? '', style: style);
  346. final tp = TextPainter(
  347. text: span, maxLines: maxLines, textDirection: TextDirection.ltr);
  348. tp.layout(maxWidth: size.maxWidth);
  349. if (tp.didExceedMaxLines) {
  350. return Column(
  351. crossAxisAlignment: CrossAxisAlignment.start,
  352. children: <Widget>[
  353. expand ?
  354. Text(text ?? '', style: style) :
  355. Text(text ?? '', maxLines: maxLines,
  356. overflow: TextOverflow.ellipsis,
  357. style: style),
  358. GestureDetector(
  359. behavior: HitTestBehavior.translucent,
  360. onTap: () {
  361. setState(() {
  362. expand = !expand;
  363. });
  364. },
  365. child: Container(
  366. padding: EdgeInsets.only(top: 2),
  367. child: Text(expand ? '收起' : '全文', style: TextStyle(
  368. fontSize: style != null ? style.fontSize : null,
  369. color: Colors.blue)),
  370. ),
  371. ),
  372. ],
  373. );
  374. } else {
  375. return Text(text ?? '', style: style);
  376. }
  377. });
  378. }
  379. }
  380. Widget ysTextExpend({String text,int maxLines,TextStyle style,bool expand = false}) {
  381. return StatefulBuilder(
  382. builder: (context,ysState){
  383. return LayoutBuilder(builder: (context, size) {
  384. final span = TextSpan(text: text ?? '', style: style);
  385. final tp = TextPainter(
  386. text: span, maxLines: maxLines, textDirection: TextDirection.ltr);
  387. tp.layout(maxWidth: size.maxWidth);
  388. if (tp.didExceedMaxLines) {
  389. return Column(
  390. crossAxisAlignment: CrossAxisAlignment.start,
  391. children: <Widget>[
  392. expand ?
  393. Text(text ?? '', style: style) :
  394. Text(text ?? '', maxLines: maxLines,
  395. overflow: TextOverflow.ellipsis,
  396. style: style),
  397. GestureDetector(
  398. behavior: HitTestBehavior.translucent,
  399. onTap: () {
  400. ysState(() {
  401. expand = !expand;
  402. });
  403. },
  404. child: Container(
  405. padding: EdgeInsets.only(top: 2),
  406. child: Text(expand ? '收起' : '全文', style: TextStyle(
  407. fontSize: style != null ? style.fontSize : null,
  408. color: Colors.blue)),
  409. ),
  410. ),
  411. ],
  412. );
  413. } else {
  414. return Text(text ?? '', style: style);
  415. }
  416. });
  417. },
  418. );
  419. }
  420. class YSPicker extends StatefulWidget {
  421. final ValueSetter choose;
  422. final List dataArray;
  423. final String title;
  424. const YSPicker({Key key, this.choose, this.dataArray, this.title}) : super(key: key);
  425. @override
  426. _YSPickerState createState() => _YSPickerState();
  427. }
  428. class _YSPickerState extends State<YSPicker> {
  429. var _value;
  430. @override
  431. Widget build(BuildContext context) {
  432. _value = widget.dataArray[0];
  433. return Container(
  434. color: Colors.transparent,
  435. height: hsp(600),
  436. child: Column(
  437. crossAxisAlignment: CrossAxisAlignment.end,
  438. children: [
  439. Container(
  440. height: hsp(100),
  441. padding: EdgeInsets.only(left: wsp(40),right: wsp(40)),
  442. decoration: BoxDecoration(
  443. color: Colors.white,
  444. border: Border(bottom: BorderSide(width: 0.5,color: Color(0xFFEEEEEE)))
  445. ),
  446. child: Row(
  447. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  448. children: [
  449. GestureDetector(
  450. child: Text('取消',style: TextStyle(fontSize: zsp(30),color: Color(0xFF999999)),),
  451. onTap: (){
  452. Navigator.pop(context);
  453. },
  454. ),
  455. GestureDetector(
  456. child: Text('确定',style: TextStyle(fontSize: zsp(30),color: Color(0xFF108DE9)),),
  457. onTap: (){
  458. widget.choose(_value);
  459. Navigator.pop(context);
  460. },
  461. )
  462. ],
  463. ),
  464. ),
  465. Container(
  466. height: hsp(500),
  467. padding: EdgeInsets.all(10),
  468. decoration: BoxDecoration(
  469. color: Colors.white,
  470. borderRadius: BorderRadius.only(topLeft: Radius.circular(20),topRight: Radius.circular(20))
  471. ),
  472. child: CupertinoPicker(
  473. children: [
  474. for(int i=0;i<widget.dataArray.length;i++)Text('${widget.dataArray[i][widget.title]}')
  475. ],
  476. itemExtent: hsp(100),
  477. onSelectedItemChanged: (value){
  478. _value = widget.dataArray[value];
  479. },
  480. ),
  481. ),
  482. ],
  483. ),
  484. );
  485. }
  486. }
  487. timeTag(String time) {
  488. DateTime date = DateTime.parse('$time 00:00:00');
  489. String tagStr;
  490. tagStr = '${date.difference(date).inHours}';
  491. if(date.difference(date).inHours>=0&&date.difference(date).inHours<24){
  492. tagStr = '今天';
  493. }else if(date.difference(date).inHours>=24&&date.difference(date).inHours<48){
  494. tagStr = '明天';
  495. }else if(date.difference(date).inHours>=48&&date.difference(date).inHours<72){
  496. tagStr = '后天';
  497. }else{
  498. switch(date.weekday){
  499. case 1: tagStr = '周一';break;
  500. case 2: tagStr = '周二';break;
  501. case 3: tagStr = '周三';break;
  502. case 4: tagStr = '周四';break;
  503. case 5: tagStr = '周五';break;
  504. case 6: tagStr = '周六';break;
  505. case 7: tagStr = '周日';break;
  506. }
  507. }
  508. return tagStr;
  509. }
  510. class DashedRect extends StatelessWidget {
  511. final Color color;
  512. final double strokeWidth;
  513. final double gap;
  514. DashedRect(
  515. {this.color = Colors.black, this.strokeWidth = 1.0, this.gap = 5.0});
  516. @override
  517. Widget build(BuildContext context) {
  518. return Container(
  519. child: Padding(
  520. padding: EdgeInsets.all(strokeWidth / 2),
  521. child: CustomPaint(
  522. painter:
  523. DashRectPainter(color: color, strokeWidth: strokeWidth, gap: gap),
  524. ),
  525. ),
  526. );
  527. }
  528. }
  529. class DashRectPainter extends CustomPainter {
  530. double strokeWidth;
  531. Color color;
  532. double gap;
  533. DashRectPainter(
  534. {this.strokeWidth = 5.0, this.color = Colors.red, this.gap = 5.0});
  535. @override
  536. void paint(Canvas canvas, Size size) {
  537. Paint dashedPaint = Paint()
  538. ..color = color
  539. ..strokeWidth = strokeWidth
  540. ..style = PaintingStyle.stroke;
  541. double x = size.width;
  542. double y = size.height;
  543. Path _topPath = getDashedPath(
  544. a: math.Point(0, 0),
  545. b: math.Point(x, 0),
  546. gap: gap,
  547. );
  548. Path _rightPath = getDashedPath(
  549. a: math.Point(x, 0),
  550. b: math.Point(x, y),
  551. gap: gap,
  552. );
  553. Path _bottomPath = getDashedPath(
  554. a: math.Point(0, y),
  555. b: math.Point(x, y),
  556. gap: gap,
  557. );
  558. Path _leftPath = getDashedPath(
  559. a: math.Point(0, 0),
  560. b: math.Point(0.001, y),
  561. gap: gap,
  562. );
  563. canvas.drawPath(_topPath, dashedPaint);
  564. canvas.drawPath(_rightPath, dashedPaint);
  565. canvas.drawPath(_bottomPath, dashedPaint);
  566. canvas.drawPath(_leftPath, dashedPaint);
  567. }
  568. Path getDashedPath({
  569. @required math.Point<double> a,
  570. @required math.Point<double> b,
  571. @required gap,
  572. }) {
  573. Size size = Size(b.x - a.x, b.y - a.y);
  574. Path path = Path();
  575. path.moveTo(a.x, a.y);
  576. bool shouldDraw = true;
  577. math.Point currentPoint = math.Point(a.x, a.y);
  578. num radians = math.atan(size.height / size.width);
  579. num dx = math.cos(radians) * gap < 0
  580. ? math.cos(radians) * gap * -1
  581. : math.cos(radians) * gap;
  582. num dy = math.sin(radians) * gap < 0
  583. ? math.sin(radians) * gap * -1
  584. : math.sin(radians) * gap;
  585. while (currentPoint.x <= b.x && currentPoint.y <= b.y) {
  586. shouldDraw
  587. ? path.lineTo(currentPoint.x, currentPoint.y)
  588. : path.moveTo(currentPoint.x, currentPoint.y);
  589. shouldDraw = !shouldDraw;
  590. currentPoint = math.Point(
  591. currentPoint.x + dx,
  592. currentPoint.y + dy,
  593. );
  594. }
  595. return path;
  596. }
  597. @override
  598. bool shouldRepaint(CustomPainter oldDelegate) {
  599. return true;
  600. }
  601. }
  602. getSecretStr(String str) {
  603. String secret = str.length==11?'****':'***********';
  604. return str.substring(0,3)+secret+str.substring(str.length-4,str.length);
  605. }
  606. isolateCountEven(var model) async {
  607. final response = ReceivePort();
  608. await Isolate.spawn(countEvent2, response.sendPort);
  609. final sendPort = await response.first;
  610. final answer = ReceivePort();
  611. sendPort.send([answer.sendPort, model]);
  612. return answer.first;
  613. }
  614. countEvent2(SendPort port) {
  615. final rPort = ReceivePort();
  616. port.send(rPort.sendPort);
  617. rPort.listen((message) {
  618. final send = message[0] as SendPort;
  619. final model = message[1];
  620. send.send(countEven(model));
  621. });
  622. }
  623. countEven(var model){
  624. }
  625. class CirclePageRoute extends PageRoute {
  626. CirclePageRoute({
  627. @required this.builder,
  628. this.transitionDuration = const Duration(milliseconds: 500),
  629. this.opaque = true,
  630. this.barrierDismissible = false,
  631. this.barrierColor,
  632. this.barrierLabel,
  633. this.maintainState = true,
  634. });
  635. final WidgetBuilder builder;
  636. @override
  637. final Duration transitionDuration;
  638. @override
  639. final bool opaque;
  640. @override
  641. final bool barrierDismissible;
  642. @override
  643. final Color barrierColor;
  644. @override
  645. final String barrierLabel;
  646. @override
  647. final bool maintainState;
  648. @override
  649. Widget buildPage(BuildContext context, Animation<double> animation,
  650. Animation<double> secondaryAnimation) {
  651. return AnimatedBuilder(
  652. animation: animation,
  653. builder: (context, child) {
  654. return ClipPath(
  655. clipper: CirclePath(animation.value),
  656. child: child,
  657. );
  658. },
  659. child: builder(context),
  660. );
  661. }
  662. }
  663. class CirclePath extends CustomClipper<Path> {
  664. CirclePath(this.value);
  665. final double value;
  666. @override
  667. Path getClip(Size size) {
  668. var path = Path();
  669. double radius =
  670. value * sqrt(size.height * size.height + size.width * size.width);
  671. path.addOval(Rect.fromLTRB(
  672. size.width - radius, -radius, size.width + radius, radius));
  673. return path;
  674. }
  675. @override
  676. bool shouldReclip(CustomClipper<Path> oldClipper) {
  677. return true;
  678. }
  679. }