YSTools.dart 19 KB

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