{"id":564,"date":"2024-03-11T01:26:15","date_gmt":"2024-03-10T17:26:15","guid":{"rendered":"https:\/\/www.muxuetianyin.cn\/?p=564"},"modified":"2024-04-14T23:28:23","modified_gmt":"2024-04-14T15:28:23","slug":"%e7%a7%bb%e5%8a%a8%e7%ab%afflutter%e7%ae%80%e5%8d%95%e5%ba%94%e7%94%a8","status":"publish","type":"post","link":"https:\/\/www.muxuetianyin.cn\/?p=564","title":{"rendered":"\u79fb\u52a8\u7aefFlutter\u7b80\u5355\u5e94\u7528"},"content":{"rendered":"\n<p><strong>Flutter<\/strong><strong>\u4ecb\u7ecd<\/strong><\/p>\n\n\n\n<p>Flutter\u662f\u8c37\u6b4c\u516c\u53f8\u5f00\u53d1\u7684\u4e00\u6b3e\u5f00\u6e90\u3001\u514d\u8d39\u7684UI\u6846\u67b6\uff0c\u53ef\u4ee5\u8ba9\u6211\u4eec\u5feb\u901f\u7684\u5728Android\u548ciOS\u4e0a\u6784\u5efa\u9ad8\u8d28\u91cf<\/p>\n\n\n\n<p>App\u3002\u5b83\u6700\u5927\u7684\u7279\u70b9\u5c31\u662f\u8de8\u5e73\u53f0\u3001\u4ee5\u53ca\u9ad8\u6027\u80fd\u3002 \u76ee\u524d Flutter \u5df2\u7ecf\u652f\u6301 iOS\u3001Android\u3001Web\u3001<\/p>\n\n\n\n<p>Windows\u3001macOS\u3001Linux\u7b49\u3002<\/p>\n\n\n\n<p>Flutter\u57fa\u4e8e\u8c37\u6b4c\u7684dart\u8bed\u8a00\uff0c\u5982\u679c\u6ca1\u6709\u4efb\u4f55Dart\u8bed\u8a00\u7684\u57fa\u7840\uff0c\u4e0d\u5efa\u8bae\u76f4\u63a5\u5b66\u4e60Flutter\u3002\u5efa\u8bae\u5148\u5b66\u4e60Dart<\/p>\n\n\n\n<p>\u8bed\u8a00\u7684\u57fa\u672c\u8bed\u6cd5\u3002\u7136\u540e\u518d\u8fdb\u5165Flutter\u7684\u5b66\u4e60\u3002<\/p>\n\n\n\n<p>Flutter \u5b98\u7f51\uff1ahttps:\/\/flflutter.dev\/<\/p>\n\n\n\n<p>Flutter Packages\u5b98\u7f51\uff1ahttps:\/\/pub.dev\/<\/p>\n\n\n\n<p><strong>\u9700\u8981\u6709\u4e00\u5b9a\u57fa\u7840\u624d\u80fd\u770b\u61c2\u6b64\u6587\u7ae0<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u9879\u76ee\u51c6\u5907<\/h2>\n\n\n\n<p>\u4e0b\u8f7d\u5b89\u88c5Flutter<\/p>\n\n\n\n<p>\u5b98\u7f51<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;flutter.cn\/docs\/get-started\/install\/windows<\/code><\/pre>\n\n\n\n<p>\u4e0b\u8f7d\u5b8c\u6210\u540e\u914d\u7f6e\u73af\u5883\u53d8\u91cf<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1024x681.png'><img loading=\"lazy\" width=\"1024\" height=\"681\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1024x681.png\" alt=\"\" class=\"wp-image-565\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1024x681.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-300x200.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-768x511.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image.png 1153w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<p>\u52a0\u5165 <code>flutter\\bin<\/code> \u76ee\u5f55\u7684\u5b8c\u6574\u8def\u5f84\u3002<\/p>\n\n\n\n<p>\u8fd0\u884c<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>where flutter dart<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1-1024x485.png'><img loading=\"lazy\" width=\"1024\" height=\"485\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1-1024x485.png\" alt=\"\" class=\"wp-image-566\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1-1024x485.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1-300x142.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1-768x364.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-1.png 1136w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<p class=\"has-medium-font-size\"><strong>androad studio\u73af\u5883\u914d\u7f6e<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-2.png'><img loading=\"lazy\" width=\"965\" height=\"708\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-2.png\" alt=\"\" class=\"wp-image-567\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-2.png 965w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-2-300x220.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-2-768x563.png 768w\" sizes=\"(max-width: 965px) 100vw, 965px\" \/><\/div><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-3-1024x657.png'><img loading=\"lazy\" width=\"1024\" height=\"657\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-3-1024x657.png\" alt=\"\" class=\"wp-image-568\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-3-1024x657.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-3-300x193.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-3-768x493.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-3.png 1153w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<p>\u5b89\u88c5\u63d2\u4ef6<\/p>\n\n\n\n<p>flutter\u548cdart<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-4-1024x737.png'><img loading=\"lazy\" width=\"1024\" height=\"737\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-4-1024x737.png\" alt=\"\" class=\"wp-image-569\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-4-1024x737.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-4-300x216.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-4-768x553.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-4.png 1153w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">\u521b\u5efaflutter\u5de5\u7a0b<\/h3>\n\n\n\n<p>Dart\u548cFlutter\u5bf9\u5305\u540d\u6709\u4e00\u4e9b\u89c4\u5b9a\uff0c\u5305\u540d\u5fc5\u987b\u5168\u90e8\u662f\u5c0f\u5199\uff0c\u5e76\u4e14\u53ea\u80fd\u5305\u542b\u5b57\u6bcd\u3001\u6570\u5b57\u548c\u4e0b\u5212\u7ebf\u3002\u6b64\u5916\uff0c\u5305\u540d\u4e0d\u80fd\u4ee5\u6570\u5b57\u5f00\u5934\u3002<\/p>\n\n\n\n<p>flutter create my_app \uff08\u8fd9\u91cc\u6211\u53ebonly_you\uff09<\/p>\n\n\n\n<p><a href=\"https:\/\/developer.android.google.cn\/studio\/run\/managing-avds?hl=zh-cn#emulator\">https:\/\/developer.android.google.cn\/studio\/run\/managing-avds?hl=zh-cn#emulator<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-5-1024x360.png'><img loading=\"lazy\" width=\"1024\" height=\"360\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-5-1024x360.png\" alt=\"\" class=\"wp-image-570\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-5-1024x360.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-5-300x105.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-5-768x270.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-5.png 1102w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<p>\u521b\u5efalogin\u7ec4\u4ef6<\/p>\n\n\n\n<p>flutter create &#8211;template=package login_sdk<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-6.png'><img loading=\"lazy\" width=\"983\" height=\"575\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-6.png\" alt=\"\" class=\"wp-image-571\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-6.png 983w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-6-300x175.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-6-768x449.png 768w\" sizes=\"(max-width: 983px) 100vw, 983px\" \/><\/div><\/figure>\n\n\n\n<p>\u5bfc\u5165<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-7-1024x306.png'><img loading=\"lazy\" width=\"1024\" height=\"306\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-7-1024x306.png\" alt=\"\" class=\"wp-image-572\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-7-1024x306.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-7-300x90.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-7-768x229.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-7.png 1153w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-8-1024x543.png'><img loading=\"lazy\" width=\"1024\" height=\"543\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-8-1024x543.png\" alt=\"\" class=\"wp-image-573\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-8-1024x543.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-8-300x159.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-8-768x407.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-8.png 1153w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<p>\u5bfc\u5165\u6d4b\u8bd5<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-9-1024x520.png'><img loading=\"lazy\" width=\"1024\" height=\"520\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-9-1024x520.png\" alt=\"\" class=\"wp-image-574\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-9-1024x520.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-9-300x152.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-9-768x390.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-9.png 1153w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">\u914d\u7f6e\u4e0b\u8f7d\u7ec4\u7ec4\u4ef6<\/h3>\n\n\n\n<p><strong>hi_download<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flutter create --template=package hi_download<\/code><\/pre>\n\n\n\n<p>\u4f9d\u8d56<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flutter pub add http\r\n\r\nflutter pub add path_provider<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'dart:io';\r\nimport 'package:flutter\/cupertino.dart';\r\nimport 'package:http\/http.dart' as http;\r\nimport 'package:path_provider\/path_provider.dart';\r\ntypedef DownLoadListener = void Function(int total,int received,bool done);\r\nclass HiDownload{\r\n  int _total = 0, _received = 0;\r\n  Future&lt;String> download({required String downLoadUrl,required String fileName,required DownLoadListener listener})\r\n  async {\r\n          debugPrint('start download');\r\n          var uri= Uri.parse(downLoadUrl);\r\n          var request=http.Request('GET',uri);\r\n          var response= await http.Client().send(request);\r\n          _total=response.contentLength??0;\r\n          var path=(await getApplicationDocumentsDirectory()).path;\r\n          final file=File('$path\/$fileName');\r\n          final writeFile=file.openSync(mode: FileMode.write);\r\n  \/\/         \u91c7\u7528stream\u907f\u514d\u5185\u5b58\u5360\u7528\uff0c\u63d0\u793a\u6027\u80fd\r\n          response.stream.listen((value) {\r\n            writeFile.writeFromSync(value);\r\n            _received+=value.length;\r\n            listener(_total,_received,false);\r\n            debugPrint('progress:${_received\/_total}');\r\n\r\n          }).onDone(() async{\r\n            await  writeFile.close();\r\n            listener(_total,_received,true);\r\n            debugPrint(\"-----done-----\");\r\n\r\n          });\r\n          return file.absolute.path;\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">\u4e3b\u9879\u76ee<\/h2>\n\n\n\n<p>yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: only_you\r\ndescription: A new Flutter project.\r\n# The following line prevents the package from being accidentally published to\r\n# pub.dev using `flutter pub publish`. This is preferred for private packages.\r\npublish_to: 'none' # Remove this line if you wish to publish to pub.dev\r\n\r\n\r\nversion: 1.0.0+1\r\n\r\nenvironment:\r\n  sdk: '>=3.1.0 &lt;4.0.0'\r\n\r\n\r\ndependencies:\r\n  flutter:\r\n    sdk: flutter\r\n\r\n\r\n  cupertino_icons: ^1.0.2\r\n#  \u7ec4\u4ef6\u5316\u914d\u7f6e\r\n  login_sdk:\r\n    path: \"..\/login_sdk\"\r\n  hi_download:\r\n    path: '..\/hi_download'\r\ndev_dependencies:\r\n  flutter_test:\r\n    sdk: flutter\r\n\r\n\r\n  flutter_lints: ^2.0.0\r\n\r\n\r\nflutter:\r\n  uses-material-design: true<\/code><\/pre>\n\n\n\n<p>\u65b0\u5efa\u6587\u4ef6\u76ee\u5f55<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-10-1024x369.png'><img loading=\"lazy\" width=\"1024\" height=\"369\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-10-1024x369.png\" alt=\"\" class=\"wp-image-575\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-10-1024x369.png 1024w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-10-300x108.png 300w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-10-768x277.png 768w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-10.png 1153w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/div><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>my_app\/\r\n\u251c\u2500\u2500 android\/\r\n\u251c\u2500\u2500 ios\/\r\n\u251c\u2500\u2500 lib\/\r\n\u2502   \u251c\u2500\u2500 main.dart\r\n\u2502   \u251c\u2500\u2500 app.dart\r\n\u2502   \u251c\u2500\u2500 config\/\r\n\u2502   \u251c\u2500\u2500 models\/\r\n\u2502   \u251c\u2500\u2500 views\/\r\n\u2502   \u2502   \u251c\u2500\u2500 pages\/\r\n\u2502   \u2502   \u251c\u2500\u2500 widgets\/\r\n\u2502   \u251c\u2500\u2500 services\/\r\n\u2502   \u251c\u2500\u2500 utils\/\r\n\u2502   \u251c\u2500\u2500 routes\/\r\n\u2502   \u2514\u2500\u2500 theme\/\r\n\u251c\u2500\u2500 test\/\r\n\u251c\u2500\u2500 pubspec.yaml\r\n\u2514\u2500\u2500 README.md\r\n\r\n- android\/ \u548c ios\/ \u76ee\u5f55\u5305\u542b\u4e86\u7279\u5b9a\u5e73\u53f0\u7684\u4ee3\u7801\u3002\r\n- lib\/ \u76ee\u5f55\u662f\u6211\u4eec\u7f16\u5199Dart\u4ee3\u7801\u7684\u5730\u65b9\u3002\r\n- main.dart \u662f\u5e94\u7528\u7a0b\u5e8f\u7684\u5165\u53e3\u70b9\u3002\r\n- app.dart \u901a\u5e38\u5305\u542b\u4e86\u5e94\u7528\u7a0b\u5e8f\u7684\u6839Widget\uff0c\u5982 MaterialApp \u6216 CupertinoApp\u3002\r\n- config\/ \u76ee\u5f55\u7528\u4e8e\u5b58\u653e\u5e94\u7528\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5982\u7f51\u7edc\u914d\u7f6e\u3001\u73af\u5883\u914d\u7f6e\u7b49\u3002\r\n- models\/ \u76ee\u5f55\u5305\u542b\u4e86\u5e94\u7528\u7a0b\u5e8f\u7684\u6570\u636e\u6a21\u578b\u3002\r\n- views\/ \u76ee\u5f55\u5305\u542b\u4e86\u5e94\u7528\u7a0b\u5e8f\u7684\u6240\u6709\u9875\u9762\u548c\u81ea\u5b9a\u4e49\u7684Widget\u3002\r\n- services\/ \u76ee\u5f55\u5305\u542b\u4e86\u4e0e\u540e\u7aefAPI\u4ea4\u4e92\u7684\u670d\u52a1\u7c7b\u3002\r\n- utils\/ \u76ee\u5f55\u5305\u542b\u4e86\u4e00\u4e9b\u5b9e\u7528\u5de5\u5177\uff0c\u5982\u7f51\u7edc\u8bf7\u6c42\u3001\u672c\u5730\u5b58\u50a8\u7b49\u3002\r\n- routes\/ \u76ee\u5f55\u5305\u542b\u4e86\u5e94\u7528\u7a0b\u5e8f\u7684\u6240\u6709\u8def\u7531\uff08\u9875\u9762\uff09\u3002\r\n- theme\/ \u76ee\u5f55\u7528\u4e8e\u5b58\u653e\u5e94\u7528\u7684\u4e3b\u9898\u6837\u5f0f\u3002\r\n- test\/ \u76ee\u5f55\u7528\u4e8e\u5b58\u653e\u6d4b\u8bd5\u4ee3\u7801\u3002\r\n- pubspec.yaml \u6587\u4ef6\u7528\u4e8e\u7ba1\u7406Flutter\u5e94\u7528\u7684\u4f9d\u8d56\u9879\u3002\r\n- README.md \u6587\u4ef6\u7528\u4e8e\u63cf\u8ff0\u9879\u76ee\u7684\u4fe1\u606f\u3002<\/code><\/pre>\n\n\n\n<p>\u8fdb\u5165\u4e3b\u9879\u76eeonly_you\u521b\u5efa<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir lib\/config lib\/models lib\/views lib\/views\/pages lib\/views\/widgets lib\/services lib\/utils lib\/routes lib\/theme<\/code><\/pre>\n\n\n\n<p>New-Item -ItemType Directory -Path .\\lib\\config<br>New-Item -ItemType Directory -Path .\\lib\\models<br>New-Item -ItemType Directory -Path .\\lib\\views<br>New-Item -ItemType Directory -Path .\\lib\\views\\pages<br>New-Item -ItemType Directory -Path .\\lib\\views\\widgets<br>New-Item -ItemType Directory -Path .\\lib\\services<br>New-Item -ItemType Directory -Path .\\lib\\utils<br>New-Item -ItemType Directory -Path .\\lib\\routes<br>New-Item -ItemType Directory -Path .\\lib\\theme<\/p>\n\n\n\n<p>\u521b\u5efaapp.dart\u6587\u4ef6\uff0c\u8fd9\u4e2a\u6587\u4ef6\u901a\u5e38\u7528\u4e8e\u5b9a\u4e49\u5e94\u7528\u7684\u4e3b\u9898\u548c\u8def\u7531\u3002\u5728lib\/\u76ee\u5f55\u4e0b\u521b\u5efaapp.dart\u6587\u4ef6\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>touch lib\/app.dart\n<\/code><\/pre>\n\n\n\n<p>\u65b0\u5efaroutes.dart<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/material.dart';\r\nimport 'package:your_project\/views\/pages\/home_page.dart';\r\nimport 'package:your_project\/views\/pages\/login_page.dart';\r\n\r\nclass Routes {\r\n  static const home = '\/';\r\n  static const login = '\/login';\r\n\r\n  static Route&lt;dynamic> generateRoute(RouteSettings settings) {\r\n    switch (settings.name) {\r\n      case home:\r\n        return MaterialPageRoute(builder: (_) => HomePage());\r\n      case login:\r\n        return MaterialPageRoute(builder: (_) => LoginPage());\r\n      default:\r\n        throw FormatException(\"Route not found\");\r\n    }\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p>\u5728home_page.dart\u6587\u4ef6\u4e2d\u521b\u5efa\u4e00\u4e2aHomePage\u7c7b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/material.dart';\r\n\r\nclass HomePage extends StatelessWidget {\r\n  @override\r\n  Widget build(BuildContext context) {\r\n    return Scaffold(\r\n      appBar: AppBar(\r\n        title: Text('Home'),\r\n      ),\r\n      body: Center(\r\n        child: Text('Welcome to Home Page'),\r\n      ),\r\n    );\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p>\u5728login_page.dart\u6587\u4ef6\u4e2d\u521b\u5efa\u4e00\u4e2aLoginPage\u7c7b\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/material.dart';\r\n\r\nclass LoginPage extends StatelessWidget {\r\n  @override\r\n  Widget build(BuildContext context) {\r\n    return Scaffold(\r\n      appBar: AppBar(\r\n        title: Text('login'),\r\n      ),\r\n      body: Center(\r\n        child: Text('Welcome to'),\r\n      ),\r\n    );\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p>\u5728app.dart\u6587\u4ef6\u4e2d<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/material.dart';\r\nimport 'views\/pages\/home_page.dart';\r\nimport 'views\/pages\/login_page.dart';\r\nimport 'routes\/routes.dart';\r\n\r\nclass MyApp extends StatelessWidget {\r\n  @override\r\n  Widget build(BuildContext context) {\r\n    return MaterialApp(\r\n      title: 'My App',\r\n      theme: ThemeData(\r\n        primarySwatch: Colors.blue,\r\n      ),\r\n      initialRoute: Routes.home,\r\n      routes: {\r\n        Routes.home: (context) => HomePage(),\r\n        Routes.login: (context) => LoginPage(),\r\n      },\r\n    );\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p>\u6216\u8005\u4e5f\u53ef\u4ee5\u76f4\u63a5\u5728app\u914d\u7f6e\u8def\u7531<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/material.dart';\r\nimport 'views\/pages\/home_page.dart';\r\nimport 'views\/pages\/login_page.dart';\r\n\r\nclass MyApp extends StatelessWidget {\r\n  @override\r\n  Widget build(BuildContext context) {\r\n    return MaterialApp(\r\n      title: 'My App',\r\n      theme: ThemeData(\r\n        primarySwatch: Colors.blue,\r\n      ),\r\n      initialRoute: '\/',\r\n      routes: {\r\n        '\/': (context) => HomePage(),\r\n        '\/login': (context) => LoginPage(),\r\n      },\r\n    );\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p>\u66f4\u65b0main.dart\u6587\u4ef6<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/material.dart';\r\nimport 'app.dart';\r\n\r\nvoid main() {\r\n  runApp(MyApp());\r\n}<\/code><\/pre>\n\n\n\n<p>\u767b\u9304\u9801\u9762<\/p>\n\n\n\n<p>\u5728widgets\u4e2d\u65b0\u5efainput_widget<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/material.dart';\nimport 'package:flutter\/services.dart';\n\nclass InputWidget extends StatelessWidget {\n  final String hint;\n  final ValueChanged&lt;String>? onChanged;\n  final bool obscureText;\n  final TextInputType? keyboardType;\n  final Widget? suffixIcon;\n  final List&lt;TextInputFormatter>? inputFormatters;\n  const InputWidget(\n      {super.key,\n      required this.hint,\n      this.onChanged,\n      this.obscureText = false,\n      this.keyboardType,\n      this.suffixIcon,\n      this.inputFormatters});\n\n  get _input {\n    return TextField(\n      \/\/ \u5f53\u8f93\u5165\u6846\u5185\u5bb9\u6539\u53d8\u65f6\uff0c\u4f1a\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570\n      onChanged: onChanged,\n      \/\/ \u662f\u5426\u9690\u85cf\u8f93\u5165\u7684\u6587\u672c\n      obscureText: obscureText,\n      \/\/ \u952e\u76d8\u7c7b\u578b\n      keyboardType: keyboardType,\n      \/\/ \u662f\u5426\u542f\u7528\u81ea\u52a8\u7ea0\u9519\uff0c\u5f53obscureText\u4e3atrue\uff08\u9690\u85cf\u8f93\u5165\u7684\u6587\u672c\uff09\u65f6\uff0c\u81ea\u52a8\u7ea0\u9519\u88ab\u7981\u7528\u3002\n      autocorrect: !obscureText,\n      \/\/ \u5149\u6807\u989c\u8272\n      cursorColor: Colors.white,\n      \/*\u8f93\u5165\u7684\u6587\u672c\u7684\u6837\u5f0f*\/\n      style: const TextStyle(\n          fontSize: 17, color: Colors.white, fontWeight: FontWeight.w500),\n      \/*\u8f93\u5165\u6846\u7684\u88c5\u9970\uff0c\u5305\u62ec\u8fb9\u6846\u3001\u63d0\u793a\u6587\u672c\u548c\u63d0\u793a\u6587\u672c\u7684\u6837\u5f0f *\/\n      decoration: InputDecoration(\n        border: InputBorder.none,\n        hintText: hint,\n        hintStyle: const TextStyle(fontSize: 17, color: Colors.grey),\n        \/\/\n        suffixIcon: suffixIcon,\n      ),\n      inputFormatters: inputFormatters,\n    );\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: &#91;\n        _input,\n        const Divider(\n          color: Colors.white,\n          height: 1,\n          thickness: 0.5,\n        )\n      ],\n    );\n  }\n}\n\n\u6a23\u5f0f\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-11.png'><img loading=\"lazy\" width=\"657\" height=\"974\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-11.png\" alt=\"\" class=\"wp-image-577\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-11.png 657w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-11-202x300.png 202w\" sizes=\"(max-width: 657px) 100vw, 657px\" \/><\/div><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><div class='fancybox-wrapper' data-fancybox='post-images' href='https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-12.png'><img loading=\"lazy\" width=\"657\" height=\"994\" src=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-12.png\" alt=\"\" class=\"wp-image-578\" srcset=\"https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-12.png 657w, https:\/\/www.muxuetianyin.cn\/wp-content\/uploads\/2024\/03\/image-12-198x300.png 198w\" sizes=\"(max-width: 657px) 100vw, 657px\" \/><\/div><\/figure>\n\n\n\n<p>\u6269\u5c55<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:flutter\/cupertino.dart';\r\n\/\/ \u6269\u5c55int\u4ee5\u65b9\u4fbf\u4f7f\u7528\r\nextension Intfix on int {\r\n  SizedBox get paddingHeight{\r\n    return SizedBox(height: toDouble(),);\r\n  }\r\n  SizedBox get paddingWidth{\r\n    return SizedBox(width: toDouble());\r\n  }\r\n}\r\n\/\/\u6269\u5c55double\u4ee5\u65b9\u4fbf\u4f7f\u7528\r\nextension Dobulefix on double{\r\n  SizedBox get paddingHeight{\r\n    return SizedBox(height: this,);\r\n  }\r\n  SizedBox get paddingWidth{\r\n    return SizedBox(width: this);\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p>\u9875\u9762\u4f7f\u7528<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>                 \/\/\u539f\u672c\r\n                  const SizedBox(height: 16.0),\r\n                  \/\/\u6269\u5c55\u6548\u679c\r\n                  16.paddingHeight<\/code><\/pre>\n\n\n\n<p>\u80cc\u666f\u6539\u6210\u672c\u5730\u7684\u65b9\u4fbf\u52a0\u8f7d<\/p>\n\n\n\n<p>\u65b0\u5efaassets<\/p>\n\n\n\n<p>yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flutter:\r\n  uses-material-design: true\r\n  assets:\r\n    - assets\/background.jpg<\/code><\/pre>\n\n\n\n<p>\u6ce8\u518c<\/p>\n\n\n\n<p>\u6ce8\u518c\u662f\u4e00\u4e2ah5\u9875\u9762<\/p>\n\n\n\n<p>\u6240\u4ee5\u9700\u8981\u8df3\u8f6c\u5230h5<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flutter pub add url_launcher<\/code><\/pre>\n\n\n\n<p>\u9875\u9762<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  _jumpRegistration() async {\n    Uri uri = Uri.parse('http:\/\/together.muxuetianyin.cn\/register');\n    if(!await launchUrl(uri,mode: LaunchMode.externalApplication)){\n      debugPrint('Could not launch $uri');\n    }\n  }\n\n<\/code><\/pre>\n\n\n\n<p>\u8bf7\u6c42<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:http\/http.dart' as http;\r\nimport 'dart:convert';\r\n\r\nclass ApiService {\r\n  static const String _baseUrl = 'https:\/\/muxuetianyin.cn\/api';\r\n  \/\/ \u767b\u5f55\u63a5\u53e3\r\n  static Future&lt;Map&lt;String, dynamic>> login(String userAccount, String userPassword) async {\r\n    var url = '$_baseUrl\/api\/user\/login';\r\n    var body = jsonEncode({\r\n      'userAccount': userAccount,\r\n      'userPassword': userPassword,\r\n    });\r\n    var response = await http.post(\r\n      Uri.parse(url),\r\n      headers: {\"Content-Type\": \"application\/json\"},\r\n      body: body,\r\n    );\r\n    if (response.statusCode == 200) {\r\n      return jsonDecode(response.body);\r\n    } else {\r\n      throw Exception('Failed to login');\r\n    }\r\n  }\r\n\/\/\r\n\r\n}<\/code><\/pre>\n\n\n\n<p>yaml<\/p>\n\n\n\n<p>shared_preferences: ^2.0.8<\/p>\n\n\n\n<p>\u6216\u8005\u7528\u53e6\u4e00\u4e2a\u5e93<\/p>\n\n\n\n<p>flutter pub add flutter_hi_cache<\/p>\n\n\n\n<p>\u9875\u9762<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  void _handleLogin() async {\r\n    try {\r\n      var result = await ApiService.login(\r\n        _usernameController.text,\r\n        _passwordController.text,\r\n      );\r\n      if (result&#91;'code'] == 0) {\r\n        print('\u767b\u5f55\u6210\u529f');\r\n        \/\/ \u8fd9\u91cc\u53ef\u4ee5\u5904\u7406\u767b\u5f55\u6210\u529f\u540e\u7684\u903b\u8f91\uff0c\u4f8b\u5982\u8df3\u8f6c\u5230\u4e3b\u9875\r\n        \/\/ \u5b58\u50a8\u8bf7\u6c42\u5934\r\n        SharedPreferences prefs = await SharedPreferences.getInstance();\r\n        await prefs.setString('Authorization', result&#91;'data']&#91;'token']);\r\n      } else {\r\n        print('\u767b\u5f55\u5931\u8d25\uff1a${result&#91;'description']}');\r\n      }\r\n    } catch (e) {\r\n      print('\u8bf7\u6c42\u5931\u8d25\uff1a$e');\r\n    }\r\n  }<\/code><\/pre>\n\n\n\n<p>LoginService<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import 'package:shared_preferences\/shared_preferences.dart';\r\nimport 'package:http\/http.dart' as http;\r\nimport 'dart:convert';\r\n\r\nclass LoginService {\r\n  static const String _baseUrl = 'https:\/\/muxuetianyin.cn';\r\n\r\n  \/\/ \u767b\u5f55\u63a5\u53e3\r\n  static Future&lt;Map&lt;String, dynamic>> login(String userAccount, String userPassword) async {\r\n    var url = '$_baseUrl\/api\/user\/login';\r\n    var body = jsonEncode({\r\n      'userAccount': userAccount,\r\n      'userPassword': userPassword,\r\n    });\r\n    var response = await http.post(\r\n      Uri.parse(url),\r\n      headers: {\"Content-Type\": \"application\/json\"},\r\n      body: body,\r\n    );\r\n    if (response.statusCode == 200) {\r\n      var result = jsonDecode(response.body);\r\n      \/\/ \u4fdd\u5b58token\r\n      SharedPreferences prefs = await SharedPreferences.getInstance();\r\n      prefs.setString(\"token\", result&#91;'data']&#91;'token']);\r\n      prefs.setString(\"refreshToken\", result&#91;'data']&#91;'refreshToken']);\r\n      return result;\r\n    } else {\r\n      throw Exception('Failed to login');\r\n    }\r\n  }\r\n  \/\/\u5237\u65b0Token\r\n  static Future&lt;Map&lt;String, dynamic>> refreshToken() async {\r\n    var url = '$_baseUrl\/api\/user\/refresh';\r\n    SharedPreferences prefs = await SharedPreferences.getInstance();\r\n    var refreshToken = prefs.getString(\"refreshToken\");\r\n    if(refreshToken == null){\r\n      throw Exception('Failed to refreshToken');\r\n    }\r\n    var body = jsonEncode({\r\n      'refreshToken': refreshToken\r\n    });\r\n    var response = await http.post(\r\n      Uri.parse(url),\r\n      headers: {\"Content-Type\": \"application\/json\"},\r\n      body: body,\r\n    );\r\n    if (response.statusCode == 200) {\r\n      var result = jsonDecode(response.body);\r\n      \/\/ \u4fdd\u5b58\u65b0\u7684 token\r\n      prefs.setString(\"token\", result&#91;'data']);\r\n      return result;\r\n    } else {\r\n      throw Exception('Failed to refreshToken');\r\n    }\r\n  }\r\n\r\n  \/\/ \u83b7\u53d6token\r\n  static Future&lt;String?> getToken() async {\r\n    SharedPreferences prefs = await SharedPreferences.getInstance();\r\n    var token = prefs.getString(\"token\");\r\n    return token;\r\n  }\r\n\r\n  \/\/ \u767b\u51fa\r\n  static Future&lt;void> logout() async {\r\n    \/\/ \u79fb\u9664token\r\n    SharedPreferences prefs = await SharedPreferences.getInstance();\r\n    prefs.remove(\"token\");\r\n    \/\/ \u8df3\u8f6c\u5230\u767b\u5f55\u9875\r\n    \/\/ ...\r\n  }\r\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Flutter\u4ecb\u7ecd Flutter\u662f\u8c37\u6b4c\u516c\u53f8\u5f00\u53d1\u7684\u4e00\u6b3e\u5f00\u6e90\u3001\u514d\u8d39\u7684UI\u6846\u67b6\uff0c\u53ef\u4ee5\u8ba9\u6211\u4eec\u5feb\u901f\u7684\u5728Android\u548c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[13],"tags":[],"_links":{"self":[{"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=\/wp\/v2\/posts\/564"}],"collection":[{"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=564"}],"version-history":[{"count":2,"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=\/wp\/v2\/posts\/564\/revisions"}],"predecessor-version":[{"id":579,"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=\/wp\/v2\/posts\/564\/revisions\/579"}],"wp:attachment":[{"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=564"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=564"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.muxuetianyin.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=564"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}