{"id":708,"date":"2023-08-03T17:46:20","date_gmt":"2023-08-03T09:46:20","guid":{"rendered":"https:\/\/iichen.cn\/?p=708"},"modified":"2025-01-23T16:02:23","modified_gmt":"2025-01-23T08:02:23","slug":"flutter-%e6%bb%91%e5%8a%a8%e6%9f%b1%e7%8a%b6%e5%9b%be","status":"publish","type":"post","link":"https:\/\/iichen.cn\/?p=708","title":{"rendered":"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png'><img class=\"lazyload lazyload-style-11\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" width=\"733\" height=\"381\" data-original=\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" alt=\"\" class=\"wp-image-750\"  sizes=\"(max-width: 733px) 100vw, 733px\" \/><\/div><\/figure>\n<\/div>\n\n<h4>1. \u8c03\u7528\u5904<\/h4>\n<pre><code class=\"language-dart line-numbers\">import 'dart:async';\n\nimport 'package:flutter\/material.dart';\nimport 'package:plano_flutter\/helpers\/router\/flutter_binding.dart';\nimport 'package:plano_flutter\/models\/event_bus.dart';\nimport 'package:plano_flutter\/modules\/home\/models\/week_slider_chart_click_config.dart';\nimport 'package:plano_flutter\/modules\/home\/models\/week_slider_chart_config.dart';\nimport 'package:plano_flutter\/modules\/home\/widget\/week_slider_chart.dart';\nimport 'package:screen_adapter\/src\/size_extension.dart';\n\nclass OutDoorSliderWeekChartWidget extends StatefulWidget {\n  List&lt;WeekSliderChartConfig&gt; realSource;\n  bool hasShowGuide;\n  Function? doLoadNext;\n  Function? onPageChange;\n  OutDoorSliderWeekChartWidget(this.realSource, {this.onPageChange,this.doLoadNext,this.hasShowGuide = false,Key? key}) : super(key: key);\n\n  @override\n  State&lt;OutDoorSliderWeekChartWidget&gt; createState() =&gt; _OutDoorSliderWeekChartWidgetState();\n}\n\nGlobalKey key = GlobalKey();\nclass _OutDoorSliderWeekChartWidgetState extends State&lt;OutDoorSliderWeekChartWidget&gt; {\n  bool hasShowGuide = false;\n\n  late StreamSubscription _streamSubscription;\n  @override\n  void initState() {\n    hasShowGuide = widget.hasShowGuide;\n    super.initState();\n  }\n\n  int _lastPage = 0;\n  \/\/ \u6240\u6709\u7684\u77e9\u5f62\u96c6\u5408\u7528\u4e8e\u5224\u65ad \u70b9\u51fb\u8303\u56f4\n  List&lt;WeekSliderChartClickConfig&gt; rectList = [];\n  \/\/ \u5f53\u524d\u9009\u4e2d\u7684\u77e9\u5f62 id\n  int _curTapId = -1;\n  @override\n  Widget build(BuildContext context) {\n    return GestureDetector(\n      key: key,\n      onTapDown: (TapDownDetails details) {\n        Offset globalPosition = details.globalPosition;\n        RenderBox? renderBox = key.currentContext?.findRenderObject() as RenderBox?;\n        Offset? localPosition = renderBox?.globalToLocal(globalPosition);\n        if(localPosition != null) {\n          bool hasFit = false;\n          rectList.forEach((config) {\n            if(config.rect.contains(localPosition)) {\n              hasFit = true;\n              _curTapId = config.id;\n            }\n          });\n          setState(() {\n            if(!hasFit){\n              _curTapId = -1;\n            }\n          });\n        }\n      },\n      child: Container(\n        clipBehavior: Clip.none,\n        width: MediaQuery.of(context).size.width,\n        height: 220.h,\n        child: Center(\n          child: PageView.builder(\n            reverse: true,\n            onPageChanged: (page) {\n              \/\/ \u52a0\u8f7d\u6570\u636e \u6dfb\u52a0\u4e00\u4e2a \u4ec5\u4ec5\u5f80\u5de6\u6ed1 \u5728\u52a0\u8f7d\n              if(page == widget.realSource.length - 2 &amp;&amp; _lastPage &lt; page) {\n                widget.doLoadNext?.call();\n              }\n              _lastPage = page;\n              if(hasShowGuide) {\n                hasShowGuide = false;\n                widget.onPageChange?.call();\n              }\n            },\n            itemCount: widget.realSource.length,\n            itemBuilder: (BuildContext context, int index) {\n              return CustomPaint(\n                painter: WeekColumnarPainter(\n                  model: widget.realSource[index],\n                  tapConfig: rectList,\n                  tapId: _curTapId,\n                ),\n              );\n            },\n          ),\n        ),\n      ),\n    );\n  }\n}\n\n<\/code><\/pre>\n<h4>2. \u81ea\u5b9a\u4e49\u7ec4\u4ef6<\/h4>\n<pre><code class=\"language-dart line-numbers\">import 'package:flutter\/material.dart';\nimport 'package:intl\/intl.dart' as intl;\nimport 'package:plano_flutter\/modules\/home\/models\/outdoor_activities.dart';\nimport 'package:plano_flutter\/modules\/home\/models\/week_slider_chart_click_config.dart';\nimport 'package:plano_flutter\/modules\/home\/models\/week_slider_chart_config.dart';\nimport 'package:plano_flutter\/res\/colors.dart';\nimport 'package:screen_adapter\/src\/size_extension.dart';\n\nclass WeekColumnarPainter extends CustomPainter {\n  late WeekSliderChartConfig model;\n\n  late Paint dashLinePaint;\n  late Paint dashTextPaint;\n  late Paint dashBottomLinePaint;\n  late Paint timeTextPaint;\n  late Paint normalRectPaint;\n  late Paint upRectPaint;\n  late Paint downRectPaint;\n  late Paint tapDashPaint;\n  late Paint tapTextBgPaint;\n  late Paint arrowPaint;\n\n  \/\/ \u9876\u90e8\u7a7a\u7684\u8ddd\u79bb\u7528\u4e8e\u7ed8\u5236 \u70b9\u51fb\u67f1\u72b6\u56fe\u663e\u793a\u5177\u4f53\u6570\u503c\n  double topSpace = 40.h;\n  int tapId = -1;\n\n  \/\/ \u70b9\u51fb\u540e\u9876\u90e8\u7ed8\u5236\u6570\u503c\u7684 \u5782\u76f4\u865a\u7ebf\u7684\u9ad8\u5ea6 default\n  double tapDashH = 17.h;\n  \/\/ \u6587\u672c\u4e0e\u80cc\u666f\u7684\u95f4\u8ddd\n  double wPadding = 6.w;\n  double hPadding = 2.h;\n\n\n  \/\/ \u4e3a\u4e86\u80fd\u591f\u663e\u793a\u5168\u70b9\u51fb\u540e \u9876\u90e8\u663e\u793a\u7684\u5177\u4f53\u6570\u503c\uff0c\u5de6\u4fa7\u9700\u8981\u7a7a\u51fa  \u4f7f\u7528\u7684\u5730\u65b9\u4e0d\u8981\u4f7f\u7528\u5de6 padding\u6216margin\n  \/\/ \u5177\u4f53\u503c\u6839\u636e\u6548\u679c\u8bbe\u7f6e\n  double leftReserve = 18.w;\n\n  List&lt;WeekSliderChartClickConfig&gt; tapConfig = [];\n\n\n  var now = DateTime.now();\n  var previousDay;\n  var formatter = intl.DateFormat('MM\/dd');\n\n  bool hasDrawCenterDashLine = false;\n  WeekColumnarPainter({\n    required this.model,\n    required this.tapConfig,\n    this.tapId = -1,\n  }) {\n    previousDay = now.subtract(Duration(days: 1));\n\n    dashLinePaint = Paint()..color = model.dashColor..strokeWidth = 1..style = PaintingStyle.stroke;\n    dashTextPaint = Paint()..color = model.dashColor;\n\n    dashBottomLinePaint = Paint()..color = model.dashBottomColor..strokeWidth = 1..style = PaintingStyle.stroke;\n\n    timeTextPaint = Paint()..color = model.textColor;\n\n    normalRectPaint = Paint()..color = model.normalColor;\n    upRectPaint = Paint()..color = model.upColor;\n    downRectPaint = Paint()..color = model.downColor;\n\n    tapDashPaint = Paint()..color = model.tapDashColor..strokeWidth = 1..style = PaintingStyle.stroke;\n    tapTextBgPaint = Paint()..color = model.tapTextBgColor..style = PaintingStyle.fill;\n\n    arrowPaint = Paint()..color = CommonColors.iconButtonColor..style = PaintingStyle.fill;\n\n\n    hasDrawCenterDashLine = false;\n    chartHeight = List.generate(model.source.length, (index) =&gt; TapWidgetConfig());\n  }\n\n  late List&lt;TapWidgetConfig&gt; chartHeight;\n  @override\n  void paint(Canvas canvas, Size size) {\n    TextPainter dashTextPainter = doGetTextPainter(\"2\u5c0f\u65f6\",model.dashTextSize,model.dashTextColor);\n    dashTextPainter.layout();\n\n    \/\/ \u8bbe\u7f6e\u5de6\u53f3padding\n    double rightGap = size.width - dashTextPainter.width - model.rightPadding;\n    \/\/ \u4e3a\u4e86\u80fd\u591f\u663e\u793a\u5168\u70b9\u51fb\u540e \u9876\u90e8\u663e\u793a\u7684\u5177\u4f53\u6570\u503c\uff0c\u5de6\u4fa7\u9700\u8981\u7a7a\u51fa  \u4f7f\u7528\u7684\u5730\u65b9\u4e0d\u8981\u4f7f\u7528\u5de6 padding\u6216margin\n    double leftGap = model.leftPadding + leftReserve;\n    \/\/ \u6700\u7ec8\u7ed8\u5236\u533a\u57df\n    double contentW = size.width - dashTextPainter.width - model.leftPadding - model.rightPadding - leftReserve;\n\n    \/\/ itemGap = 0.7itemW \u8ba1\u7b97\u51fa\u7684 11\n    double itemW = contentW \/ 10;\n    double itemGap = (contentW - 7 * itemW) \/ 6;\n\n    double startX = leftGap;\n\n\n    double realH = 0;\n    \/\/ \u7ed8\u5236\u865a\u7ebf\u4e0b\u7684\u6587\u672c\n    for(int i = 0;i &lt; model.source.length;i++) {\n      Day weekModel = model.source[i];\n\n      \/\/ 2023-10-25\n      \/\/ 12 \u6362\u6210\u6570\u7ec4\u91cc\u6700\u5927\u7684\u90a3\u4e2a  mock\u6570\u636e \u6700\u5927\u662f\u8fd9\u4e2a\n      String timeStr = weekModel.dateStr??\"\";\n      TextPainter textPainter = doGetTextPainter(\"$timeStr\",model.textSize,model.textColor);\n      textPainter.layout();\n      double textHeight = textPainter.height;\n      double textWidth = textPainter.width;\n\n      \/\/ \u4f7f\u5f97\u77e9\u5f62\u4e2d\u5fc3\u4e0e \u6587\u672c\u4e2d\u5fc3\u5bf9\u9f50\n      double rectCenter = startX + itemW \/ 2;\n      Offset offset = Offset(rectCenter - textWidth \/ 2, size.height - textHeight - 1.h);\n      textPainter.paint(canvas, offset);\n\n      \/\/ \u4fee\u6b63\u77e9\u5f62\u7b49 \u6700\u5e95\u90e8\u9ad8\u5ea6\n      realH = size.height - textHeight - 6.h;\n\n      \/\/ \u80cc\u666f\u9ed8\u8ba4\u77e9\u5f62\n      RRect rRect = RRect.fromLTRBAndCorners(startX, topSpace, startX + itemW, realH, topLeft: Radius.circular(5), topRight: Radius.circular(5));\n      canvas.drawRRect(rRect, normalRectPaint);\n\n      \/\/ \u7ed8\u5236\u4e2d\u95f4\u865a\u7ebf\n      drawDashLine(canvas,rightGap,(realH - topSpace) \/ 2 + topSpace,model.dashGap,model.dashWidth,dashLinePaint);\n      if(!hasDrawCenterDashLine) {\n        hasDrawCenterDashLine = true;\n        \/\/ \u7ed8\u5236\u4e2d\u5fc3\u865a\u7ebf\u5bf9\u5e94\u7684\u6587\u672c\n        Offset dashOffset = Offset(rightGap + 5, (realH - dashTextPainter.height - topSpace) \/ 2 + topSpace);\n        dashTextPainter.paint(canvas, dashOffset);\n      }\n\n      \/*\n            y&gt;=2\u65f6  x = 100 - 100 \/ y\n            y&lt;2\u65f6  x = y * 25\n       *\/\n      double hour = weekModel.hours??0;\n      \/\/ \u6d4b\u8bd5\u6253\u5f00\n      \/\/ if(formatDate(weekModel.dateStr??\"\") == \"06\/07\"){\n      \/\/   hour = 10;\n      \/\/ }\n      double ratio = 1.0;\n      if(hour &lt; 2) {\n        ratio = hour * 25 \/ 100;\n      } else if(hour &gt;= 24){\n        ratio = 1.0;\n      } else {\n        ratio = (100 - 100 \/ hour) \/ 100;\n      }\n\n      double barTopHeight = topSpace + (realH - topSpace) * (1 - ratio);\n      chartHeight[i]..chartCenter = rectCenter..chartHeight = barTopHeight;\n      RRect rect = RRect.fromLTRBAndCorners(startX, barTopHeight , startX + itemW, realH, topLeft: Radius.circular(5), topRight: Radius.circular(5));\n      \/\/ 2\u5c0f\u65f6\u662f\u5206\u754c\u7ebf\n      canvas.drawRRect(rect,hour &gt;= 2 ? upRectPaint : downRectPaint);\n      tapConfig.add(WeekSliderChartClickConfig()\n        ..rect = rect\n        ..id = weekModel.hashCode\n      );\n\n      startX += itemW + itemGap;\n    }\n\n    \/\/ \u5e95\u90e8\u865a\u7ebf\n    drawDashLine(canvas,rightGap,realH,model.dashBottomGap,model.dashWidth,dashBottomLinePaint);\n\n    for(int i = 0;i &lt; model.source.length;i++) {\n      Day weekModel = model.source[i];\n      if(weekModel.hashCode == tapId) {\n        TapWidgetConfig config = chartHeight[i];\n\n        TextPainter textPainter = doGetTextPainter(\"${weekModel.hours??0}\u5c0f\u65f6\",model.tapTextSize,model.tapTextColor,fontWeight: model.tapTextWeight);\n        textPainter.layout();\n        double textHeight = textPainter.height;\n        double textWidth = textPainter.width;\n\n        \/\/ 16.w \u540c\u4e0a\u662f\u4e0etext\u7684\u95f4\u8ddd\n        double bgWidth = textWidth + wPadding * 2;\n        RRect rect = RRect.fromLTRBAndCorners(\n            config.chartCenter - bgWidth \/ 2,\n            config.chartHeight - tapDashH - textHeight - hPadding * 2,\n            config.chartCenter + bgWidth \/ 2 ,\n            config.chartHeight - tapDashH,\n            topLeft: Radius.circular(4.r),\n            topRight: Radius.circular(4.r),\n            bottomLeft: Radius.circular(4.r),\n            bottomRight: Radius.circular(4.r));\n        canvas.drawRRect(rect,tapTextBgPaint);\n\n        \/\/ \u4f7f\u5f97\u77e9\u5f62\u4e2d\u5fc3\u4e0e \u6587\u672c\u4e2d\u5fc3\u5bf9\u9f50 2.h \u662fText\u4e0e\u5176\u5706\u89d2\u80cc\u666f\u7684\u95f4\u8ddd\n        Offset offset = Offset(config.chartCenter - textWidth \/ 2,config.chartHeight - tapDashH - textHeight - hPadding);\n        textPainter.paint(canvas, offset);\n\n        drawVerticalDashLine(canvas, config.chartCenter, config.chartHeight,model.dashGap, 2, tapDashPaint);\n      }\n    }\n    \/\/ \u7ed8\u5236\u70b9\u51fb\u65f6 \u9876\u90e8\u6570\u503c\n\n    \/\/ \u7ed8\u5236\u5f15\u5bfc  \u7bad\u5934\u81ea\u5df1\u7ed8\u5236\n    \/\/ if(true) {\n    \/\/   Path path = Path()\n    \/\/     ..moveTo(leftGap, 3 + topSpace)\n    \/\/     \/\/\/ -\n    \/\/     ..lineTo(leftGap + 18.w, 3 + topSpace)\n    \/\/     \/\/\/ |\n    \/\/     ..lineTo(leftGap + 18.w, 0 + topSpace)\n    \/\/     \/\/\/ \\\n    \/\/     ..lineTo(leftGap + 23.w, 5 + topSpace)\n    \/\/     \/\/\/ \/\n    \/\/     ..lineTo(leftGap + 18.w, 10 + topSpace)\n    \/\/     \/\/\/ |\n    \/\/     ..lineTo(leftGap + 18.w, 7 + topSpace)\n    \/\/     \/\/\/ -\n    \/\/     ..lineTo(leftGap, 7 + topSpace)\n    \/\/     ..close();\n    \/\/   canvas.drawPath(path, arrowPaint);\n    \/\/\n    \/\/   TextPainter tipPainter = doGetTextPainter(\"\u6ed1\u52a8\u67e5\u770b\u66f4\u591a\",model.textSize,model.textColor);\n    \/\/   tipPainter.layout();\n    \/\/   double textHeight = tipPainter.height;\n    \/\/   Offset offset = Offset(leftGap + 27.w, topSpace - textHeight \/ 2);\n    \/\/   tipPainter.paint(canvas, offset);\n    \/\/ }\n  }\n\n  String formatDate(String dateStr) {\n    if(dateStr.isEmpty)\n      return \"\";\n    DateTime dateTime = DateTime.parse(dateStr);\n    String month = dateTime.month.toString().padLeft(2, '0');\n    String day = dateTime.day.toString().padLeft(2, '0');\n    return '$month\/$day';\n  }\n\n  TextPainter doGetTextPainter(String text,double fontSize,Color fontColor,{FontWeight? fontWeight}) {\n    TextSpan textSpan = TextSpan(\n      text: text,\n      style: TextStyle(\n        fontSize: fontSize,\n        color: fontColor,\n        fontWeight: fontWeight,\n        height: 1.0\n      ),\n    );\n    TextPainter textPainter = TextPainter(\n        text: textSpan,\n        textAlign: TextAlign.center,\n        textDirection: TextDirection.ltr\n    );\n    return textPainter;\n  }\n\n  void drawDashLine(Canvas canvas,double w,double h,double gap,double dashWidth,Paint paint) {\n    Path path = Path();\n    double startW = leftReserve;\n    for(;startW &lt;= w;startW += dashWidth + gap){\n      path.moveTo(startW, h);\n      path.lineTo(startW + dashWidth, h);\n    }\n    canvas.drawPath(path, paint);\n  }\n\n  \/\/ x\u56fa\u5b9a\n  void drawVerticalDashLine(Canvas canvas,double x,double h,double gap,double dashHeight,Paint paint) {\n    Path path = Path();\n    double startH = h;\n    for(;startH &gt;= h - tapDashH;startH -= dashHeight + gap){\n      path.moveTo(x, startH);\n      path.lineTo(x, startH - dashHeight);\n    }\n    canvas.drawPath(path, paint);\n  }\n\n\n  @override\n  bool shouldRepaint(covariant WeekColumnarPainter oldDelegate) {\n    \/\/ \u6570\u636e\u4e0d\u540c\u6216\u70b9\u51fb\u6216\u6570\u636e\u53d8\u66f4\u8fdb\u884c\u5237\u65b0\n    return oldDelegate.model.hashCode != model.hashCode\n        || oldDelegate.tapId != tapId;\n  }\n}\n\n\/\/ \u7ed8\u5236\u9009\u4e2d \u9876\u90e8\u6307\u793a\u5668\nclass TapWidgetConfig {\n  double chartHeight = 0;\n  double chartCenter = 0;\n}\n<\/code><\/pre>\n<h4>3. \u914d\u7f6e\u9879<\/h4>\n<pre><code class=\"language-dart line-numbers\">import 'package:flutter\/material.dart';\nimport 'package:plano_flutter\/modules\/home\/models\/outdoor_activities.dart';\n\n\nclass WeekSliderChartConfig {\n  List&lt;Day&gt; source = [];\n\n  bool hasShowGuide = false;\n\n  double leftPadding = 0;\n  double rightPadding = 0;\n  double factor = 0;\n  double maxWidth = 0;\n\n  double dashWidth = 0;\n\n  int dashTime = 0;\n  Color dashColor = Color(0xff59C889);\n  Color dashTextColor = Color(0xff59C889);\n  double dashTextSize = 0;\n  double dashGap = 0;\n\n  Color normalColor = Color(0xffF6F8FA);\n  Color upColor = Color(0xff59C889);\n  Color downColor = Color(0xffFFAA4D);\n\n  Color dashBottomColor = Color(0xffcccccc);\n  double dashBottomGap = 0;\n\n  Color textColor = Color(0xff999999);\n  double textSize = 0;\n\n  \/\/ \u9876\u90e8\u70b9\u51fb\u663e\u793a\u7684\u6570\u503c\n  Color tapDashColor = Color(0xff999999);\n  Color tapTextColor = Color(0xff333333);\n  double tapTextSize = 14;\n  FontWeight tapTextWeight = FontWeight.bold;\n  Color tapTextBgColor = Color(0xffeeeeee);\n\n\n  @override\n  bool operator ==(Object other) =&gt;\n      identical(this, other) ||\n      other is WeekSliderChartConfig &amp;&amp;\n          runtimeType == other.runtimeType &amp;&amp;\n          source == other.source;\n\n  @override\n  int get hashCode =&gt; source.hashCode;\n}\n\n\nclass Day {\n  Day();\n\n  String? dateStr;\n  double? hours;\n\n  factory Day.fromJson(Map&lt;String, dynamic&gt; json) =&gt;\n  _$DayFromJson(json);\n\n  toJson() =&gt; _$DayToJson(this);\n\n  @override\n  bool operator ==(Object other) =&gt;\n  identical(this, other) ||\n  other is Day &amp;&amp;\n  runtimeType == other.runtimeType &amp;&amp;\n  dateStr == other.dateStr &amp;&amp;\n  hours == other.hours;\n\n  @override\n  int get hashCode =&gt; dateStr.hashCode ^ hours.hashCode;\n}\n<\/code><\/pre>","protected":false},"excerpt":{"rendered":"<p>1. \u8c03\u7528\u5904 import &#8216;dart:async&#8217;; import &#8216;package:flutter\/mat [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,8],"tags":[],"class_list":["post-708","post","type-post","status-publish","format-standard","hentry","category-flutter","category-8"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe - IIchen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/iichen.cn\/?p=708\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe - IIchen\" \/>\n<meta property=\"og:description\" content=\"1. \u8c03\u7528\u5904 import &#039;dart:async&#039;; import &#039;package:flutter\/mat [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/iichen.cn\/?p=708\" \/>\n<meta property=\"og:site_name\" content=\"IIchen\" \/>\n<meta property=\"article:published_time\" content=\"2023-08-03T09:46:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-01-23T08:02:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png\" \/>\n<meta name=\"author\" content=\"iichen\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"iichen\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/iichen.cn\/?p=708#article\",\"isPartOf\":{\"@id\":\"https:\/\/iichen.cn\/?p=708\"},\"author\":{\"name\":\"iichen\",\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\"},\"headline\":\"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe\",\"datePublished\":\"2023-08-03T09:46:20+00:00\",\"dateModified\":\"2025-01-23T08:02:23+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/iichen.cn\/?p=708\"},\"wordCount\":1,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\"},\"image\":{\"@id\":\"https:\/\/iichen.cn\/?p=708#primaryimage\"},\"thumbnailUrl\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png\",\"articleSection\":[\"Flutter\",\"\u7b14\u8bb0\"],\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/iichen.cn\/?p=708#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/iichen.cn\/?p=708\",\"url\":\"https:\/\/iichen.cn\/?p=708\",\"name\":\"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe - IIchen\",\"isPartOf\":{\"@id\":\"https:\/\/iichen.cn\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/iichen.cn\/?p=708#primaryimage\"},\"image\":{\"@id\":\"https:\/\/iichen.cn\/?p=708#primaryimage\"},\"thumbnailUrl\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png\",\"datePublished\":\"2023-08-03T09:46:20+00:00\",\"dateModified\":\"2025-01-23T08:02:23+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/iichen.cn\/?p=708#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/iichen.cn\/?p=708\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/iichen.cn\/?p=708#primaryimage\",\"url\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png\",\"contentUrl\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png\",\"width\":733,\"height\":381},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/iichen.cn\/?p=708#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/iichen.cn\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/iichen.cn\/#website\",\"url\":\"https:\/\/iichen.cn\/\",\"name\":\"IIchen\",\"description\":\"Just do it!\",\"publisher\":{\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/iichen.cn\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"zh-Hans\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c\",\"name\":\"iichen\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg\",\"contentUrl\":\"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg\",\"width\":940,\"height\":940,\"caption\":\"iichen\"},\"logo\":{\"@id\":\"https:\/\/iichen.cn\/#\/schema\/person\/image\/\"},\"sameAs\":[\"https:\/\/www.iichen.cn\"],\"url\":\"https:\/\/iichen.cn\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe - IIchen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/iichen.cn\/?p=708","og_locale":"zh_CN","og_type":"article","og_title":"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe - IIchen","og_description":"1. \u8c03\u7528\u5904 import 'dart:async'; import 'package:flutter\/mat [&hellip;]","og_url":"https:\/\/iichen.cn\/?p=708","og_site_name":"IIchen","article_published_time":"2023-08-03T09:46:20+00:00","article_modified_time":"2025-01-23T08:02:23+00:00","og_image":[{"url":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png","type":"","width":"","height":""}],"author":"iichen","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"iichen","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"3 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/iichen.cn\/?p=708#article","isPartOf":{"@id":"https:\/\/iichen.cn\/?p=708"},"author":{"name":"iichen","@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c"},"headline":"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe","datePublished":"2023-08-03T09:46:20+00:00","dateModified":"2025-01-23T08:02:23+00:00","mainEntityOfPage":{"@id":"https:\/\/iichen.cn\/?p=708"},"wordCount":1,"commentCount":0,"publisher":{"@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c"},"image":{"@id":"https:\/\/iichen.cn\/?p=708#primaryimage"},"thumbnailUrl":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png","articleSection":["Flutter","\u7b14\u8bb0"],"inLanguage":"zh-Hans","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/iichen.cn\/?p=708#respond"]}]},{"@type":"WebPage","@id":"https:\/\/iichen.cn\/?p=708","url":"https:\/\/iichen.cn\/?p=708","name":"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe - IIchen","isPartOf":{"@id":"https:\/\/iichen.cn\/#website"},"primaryImageOfPage":{"@id":"https:\/\/iichen.cn\/?p=708#primaryimage"},"image":{"@id":"https:\/\/iichen.cn\/?p=708#primaryimage"},"thumbnailUrl":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png","datePublished":"2023-08-03T09:46:20+00:00","dateModified":"2025-01-23T08:02:23+00:00","breadcrumb":{"@id":"https:\/\/iichen.cn\/?p=708#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/iichen.cn\/?p=708"]}]},{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/iichen.cn\/?p=708#primaryimage","url":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png","contentUrl":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/zhuzhuangtu.png","width":733,"height":381},{"@type":"BreadcrumbList","@id":"https:\/\/iichen.cn\/?p=708#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/iichen.cn\/"},{"@type":"ListItem","position":2,"name":"Flutter-\u6ed1\u52a8\u67f1\u72b6\u56fe"}]},{"@type":"WebSite","@id":"https:\/\/iichen.cn\/#website","url":"https:\/\/iichen.cn\/","name":"IIchen","description":"Just do it!","publisher":{"@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/iichen.cn\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"zh-Hans"},{"@type":["Person","Organization"],"@id":"https:\/\/iichen.cn\/#\/schema\/person\/4a47edf85ab49841df9e8f6aee40b77c","name":"iichen","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/iichen.cn\/#\/schema\/person\/image\/","url":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg","contentUrl":"https:\/\/iichen.cn\/wp-content\/uploads\/2025\/01\/avatar.jpg","width":940,"height":940,"caption":"iichen"},"logo":{"@id":"https:\/\/iichen.cn\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/www.iichen.cn"],"url":"https:\/\/iichen.cn\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/posts\/708","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=708"}],"version-history":[{"count":2,"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/posts\/708\/revisions"}],"predecessor-version":[{"id":754,"href":"https:\/\/iichen.cn\/index.php?rest_route=\/wp\/v2\/posts\/708\/revisions\/754"}],"wp:attachment":[{"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=708"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=708"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/iichen.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=708"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}