[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-9277":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":16,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":38,"readmeContent":39,"aiSummary":40,"trendingCount":16,"starSnapshotCount":16,"syncStatus":41,"lastSyncTime":42,"discoverSource":43},9277,"flustars","Sky24n\u002Fflustars","Sky24n","🔥🔥🔥  Flutter common utils library. SpUtil, ScreenUtil,WidgetUtil.  也许是目前最好用的SharedPreferences工具类。WidgetUtil 获取图片尺寸宽高, View尺寸&在屏幕上的坐标。","",null,"Dart",1921,237,35,12,0,55.13,"BSD 2-Clause \"Simplified\" License",false,"master",true,[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"dateutil","dioutil","directoryutil","endecodeutil","logutil","moneyutil","numutil","objectutil","regexutil","screenutil","sputil","textutil","timelineutil","timerutil","widgetutil","2026-06-12 04:00:43","Language: [English](README-EN.md) | 中文简体\n\n[![Pub](https:\u002F\u002Fimg.shields.io\u002Fpub\u002Fv\u002Fflustars.svg?style=flat-square&color=009688)](https:\u002F\u002Fpub.dartlang.org\u002Fpackages\u002Fflustars)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[![Pub](https:\u002F\u002Fimg.shields.io\u002Fpub\u002Fv\u002Fflustars.svg?style=flat-square&color=2196F3)](https:\u002F\u002Fpub.flutter-io.cn\u002Fpackages\u002Fflustars)\n\n# Flutter常用工具类库\n\nflustars依赖于Dart常用工具类库[common_utils](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fcommon_utils),以及对其他第三方库封装，致力于为大家分享简单易用工具类。如果你有好的工具类欢迎PR.  \n目前包含SharedPreferences Util, Screen Util, Directory Util, Widget Util, Image Util。\n\n[✓] Flutter (Channel stable, v2.0.0, locale zh-Hans-CN)\n\n### Pub\n```yaml\ndependencies:\n  flustars: ^2.0.1\n  \n  # https:\u002F\u002Fgithub.com\u002FSky24n\u002Fsp_util\n  # sp_util分拆成单独的库，可以直接引用\n  sp_util: ^2.0.3\n```\n\n### [Change Log](CHANGE_LOG.md)\nv2.0.0  \nMigrate to null-safety.\n\nv0.3.3  \n分拆[sp_util](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fsp_util)成单独的库，可以直接引用\n\n[common_utils](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fcommon_utils)新版本v1.2.0。  \n如果项目中使用了 flustars: ^0.2.6及以上版本。  \n删除pubspec.lock文件，直接运行flutter  packages get 即可使用最新版！  \n  \ncommon_utils v1.2.0  \n1、新增JsonUtil。  \n2、新增EncryptUtil 简单加解密。  \n3、LogUtil 更新。\n```yaml\nString objStr = \"{\\\"name\\\":\\\"成都市\\\"}\";\nCity hisCity = JsonUtil.getObj(objStr, (v) => City.fromJson(v));\nString listStr = \"[{\\\"name\\\":\\\"成都市\\\"}, {\\\"name\\\":\\\"北京市\\\"}]\";\nList\u003CCity> cityList = JsonUtil.getObjList(listStr, (v) => City.fromJson(v));\n\nconst String key = '11, 22, 33, 44, 55, 66';\nString value = 'Sky24n';\nString encode = EncryptUtil.xorBase64Encode(value, key); \u002F\u002F WH1YHgMs\nString decode = EncryptUtil.xorBase64Decode(encode, key); \u002F\u002F Sky24n\n\n\u002F\u002F超长log查看\ncommon_utils e  — — — — — — — — — — — — — — — — st — — — — — — — — — — — — — — — —\ncommon_utils e | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,\ncommon_utils e | 7,988,989,990,991,992,993,994,995,996,997,998,999,\ncommon_utils e  — — — — — — — — — — — — — — — — ed — — — — — — — — — — — — — — — —\n```\n\n### [Flutter工具类库 flustars][flustars_github]\n 1、SpUtil       : 单例\"同步\"SharedPreferences工具类。支持get传入默认值，支持存储对象，支持存储对象数组。  \n 2、ScreenUtil   : 屏幕适配，获取屏幕宽、高、密度，AppBar高，状态栏高度，屏幕方向.  \n 3、WidgetUtil   : 监听Widget渲染状态，获取Widget宽高，在屏幕上的坐标，获取网络\u002F本地图片尺寸.  \n 4、DioUtil      : 单例Dio网络工具类(已迁移至此处[DioUtil](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflutter_wanandroid\u002Fblob\u002Fmaster\u002Flib\u002Fdata\u002Fnet\u002Fdio_util.dart))。  \n 5、ImageUtil    : 获取网络\u002F本地图片尺寸.\n\n### [Dart常用工具类库 common_utils][common_utils_github]  \n 1、TimelineUtil : 时间轴.(新)  \n 2、TimerUtil    : 倒计时，定时任务.(新)  \n 3、MoneyUtil    : 精确转换，元转分，分转元，支持格式输出.(新)  \n 4、LogUtil      : 简单封装打印日志.(新)  \n 5、DateUtil     : 日期转换格式化输出.  \n 6、RegexUtil    : 正则验证手机号，身份证，邮箱等等.  \n 7、NumUtil      : 保留x位小数, 精确加、减、乘、除, 防止精度丢失.  \n 8、ObjectUtil   : 判断对象是否为空(String List Map),判断两个List是否相等.  \n 9、TextUtil     : TextUtil.  \n 10、EncryptUtil : EncryptUtil.  \n 11、JsonUtil    : JsonUtil.\n\n### APIs\n\n* #### SpUtil -> [Example](.\u002Fexample\u002Flib\u002Fmain.dart)\n```dart\ngetObj\ngetObjList\nputObject\ngetObject\nputObjectList\ngetObjectList\ngetString\nputString\ngetBool\nputBool\ngetInt\nputInt\ngetDouble\nputDouble\ngetStringList\nputStringList\ngetDynamic\nhaveKey\ngetKeys\nremove\nclear\nisInitialized\n  \n  \n\u002F\u002F\u002F SpUtil使用：\n\u002F\u002F\u002F 方式一\n\u002F\u002F\u002F 等待sp初始化完成后再运行app。\n\u002F\u002F\u002F sp初始化时间 release模式下30ms左右，debug模式下100多ms。\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await SpUtil.getInstance();\n  runApp(MyApp());\n}\n\nclass MyAppState extends State\u003CMyApp> {\n  @override\n  void initState() {\n    super.initState();\n    \u002F\u002F\u002F 同步使用Sp。\n    \u002F\u002F\u002F 存取基础类型\n    SpUtil.putString(\"username\", \"Sky24n\");\n    String userName = SpUtil.getString(\"username\");\n    print(\"MyHomePage userName: \" + userName);\n    \n    bool isFirst = SpUtil.getBool(\"userName\", defValue: true);\n    SpUtil.putBool(\"isFirst\", false);\n    print(\"MyHomePage isFirst: $isFirst\");\n    \n    \u002F\u002F\u002F save object example.\n    \u002F\u002F\u002F 存储实体对象示例。\n    City city = new City();\n    city.name = \"成都市\";\n    SpUtil.putObject(\"loc_city\", city);\n    \n    City hisCity = SpUtil.getObj(\"loc_city\", (v) => City.fromJson(v));\n    print(\"City: \" + (hisCity == null ? \"null\" : hisCity.toString()));\n    \n    \u002F\u002F\u002F save object list example.\n    \u002F\u002F\u002F 存储实体对象list示例。\n    List\u003CCity> list = new List();\n    list.add(new City(name: \"成都市\"));\n    list.add(new City(name: \"北京市\"));\n    SpUtil.putObjectList(\"loc_city_list\", list);\n    \n    List\u003CCity> _cityList = SpUtil.getObjList(\"loc_city_list\", (v) => City.fromJson(v));\n    print(\"City list: \" + (_cityList == null ? \"null\" : _cityList.toString()));\n  }\n  \n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp();\n  }\n}\n\n```\n\n* #### ScreenUtil -> [Example](.\u002Fexample\u002Flib\u002Fmain.dart) \n```\ngetWidth                  : 返回根据屏幕宽适配后尺寸.\ngetHeight                 : 返回根据屏幕高适配后尺寸.\ngetWidthPx                : 返回根据屏幕宽适配后尺寸.\ngetHeightPx               : 返回根据屏幕高适配后尺寸.\ngetSp                     : 返回根据屏幕宽适配后字体尺寸.\nscreenWidth               : 获取屏幕宽.\nscreenHeight              : 获取屏幕高.\nscreenDensity             : 获取屏幕密度.\nappBarHeight              : 获取系统AppBar高度.\nstatusBarHeight           : 获取系统状态栏高度.\ngetScreenW(ctx)           : 当前屏幕 宽.\ngetScreenH(ctx)           : 当前屏幕 高.\ngetStatusBarH(ctx)        : 当前状态栏高度.\ngetBottomBarH(ctx)        : 当前BottomBar高度.\ngetScaleW(ctx,size)       : 返回根据屏幕宽适配后尺寸.\ngetScaleH(ctx,size)       : 返回根据屏幕高适配后尺寸.\ngetScaleSp(ctx,size)      : 返回根据屏幕宽适配后字体尺寸.  \ngetScaleSp(ctx,size)      : 返回根据屏幕宽适配后字体尺寸.  \n\n\u002F\u002F\u002F旧适配方法仅适用于纵屏适配。\n\u002F\u002F\u002F推荐使用以下新适配方法。\ngetAdapterSize(size)             : 返回适配后尺寸，可用于宽，高，字体尺寸.  \ngetAdapterSizeCtx(ctx,size)      : 返回适配后尺寸，可用于宽，高，字体尺寸.   \n\ndouble adapterSize = ScreenUtil.getInstance().getAdapterSize(100);\ndouble adapterSize = ScreenUtil.getAdapterSizeCtx(context, 100);\n  \n一、不依赖context\n\u002F\u002F 屏幕宽\ndouble screenWidth = ScreenUtil.getInstance().screenWidth;\n\u002F\u002F 屏幕高\ndouble screenHeight = ScreenUtil.getInstance().screenHeight;\n\u002F\u002F 屏幕像素密度\ndouble screenDensity = ScreenUtil.getInstance().screenDensity;\n\u002F\u002F 系统状态栏高度\ndouble statusBarHeight = ScreenUtil.getInstance().statusBarHeight;\n\u002F\u002F BottomBar高度 \ndouble bottomBarHeight = ScreenUtil.getInstance().bottomBarHeight;\n\u002F\u002F 系统AppBar高度\ndouble appBarHeight = ScreenUtil.getInstance().appBarHeight;\n\u002F\u002F 根据屏幕宽适配后尺寸\ndouble adapterW100 = ScreenUtil.getInstance().getWidth(100);\n\u002F\u002F 根据屏幕高适配后尺寸\ndouble adapterH100 = ScreenUtil.getInstance().getHeight(100);\n\u002F\u002F 根据屏幕宽适配后字体尺寸\ndouble adapterSp100 = ScreenUtil.getInstance().getSp(100);\n\u002F\u002F 根据屏幕宽适配后尺寸(输入px)\ndouble adapterW100px = ScreenUtil.getInstance().getWidthPx(300);\n\u002F\u002F 根据屏幕高适配后尺寸(输入px)\ndouble adapterH100px = ScreenUtil.getInstance().getHeightPx(300);\n  \n二、依赖context\n\u002F\u002F 屏幕宽\ndouble screenWidth = ScreenUtil.getScreenW(context);\n\u002F\u002F 屏幕高\ndouble screenHeight = ScreenUtil.getScreenH(context);\n\u002F\u002F 屏幕像素密度\ndouble screenDensity = ScreenUtil.getScreenDensity(context);\n\u002F\u002F 系统状态栏高度\ndouble statusBarHeight = ScreenUtil.getStatusBarH(context);\n\u002F\u002F BottomBar高度\ndouble bottomBarHeight = ScreenUtil.getBottomBarH(context);\n\u002F\u002F 根据屏幕宽适配后尺寸\ndouble adapterW100 = ScreenUtil.getScaleW(context, 100);\n\u002F\u002F 根据屏幕高适配后尺寸\ndouble adapterH100 = ScreenUtil.getScaleH(context, 100);\n\u002F\u002F 根据屏幕宽适配后字体尺寸\ndouble adapterSp100 = ScreenUtil.getScaleSp(context, 100);\n\u002F\u002F 屏幕方向\nOrientation orientation = ScreenUtil.getOrientation(context);\n\n```\n\n* #### DirectoryUtil\n```\nsetInitDir\ninitTempDir\ninitAppDocDir\ninitAppSupportDir\ninitStorageDir\ncreateDirSync\ncreateDir\ngetTempPath\ngetAppDocPath\ngetAppSupportPath\ngetStoragePath\ncreateTempDirSync\ncreateAppDocDirSync\ncreateStorageDirSync\ncreateTempDir\ncreateAppDocDir\ncreateStorageDir\n\n    await DirectoryUtil.getInstance();\n    String tempPath = DirectoryUtil.getTempPath(\n        category: 'Pictures', fileName: 'demo', format: 'png');\n    print(\"thll  tempPath: $tempPath\");\n\n    String appDocPath = DirectoryUtil.getAppDocPath(\n        category: 'Pictures', fileName: 'demo', format: 'png');\n    print(\"thll  appDocPath: $appDocPath\");\n\n    String appSupportPath = DirectoryUtil.getAppSupportPath(\n        category: 'Pictures', fileName: 'demo', format: 'png');\n    print(\"thll  appSupportPath: $appSupportPath\");\n\n    String storagePath = DirectoryUtil.getStoragePath(\n        category: 'Pictures', fileName: 'demo', format: 'png');\n    print(\"thll  storagePath: $storagePath\");\n\n```\n\n* #### WidgetUtil -> [Example1](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflutter_wanandroid\u002Fblob\u002Fmaster\u002Flib\u002Fdemos\u002Fwidget_page.dart)，[Example2](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflutter_wanandroid\u002Fblob\u002Fmaster\u002Flib\u002Fdemos\u002Fimage_size_page.dart)\n```\nasyncPrepare              : Widget渲染监听，监听widget宽高变化,callback返回宽高等参数.\ngetWidgetBounds           : 获取widget 宽高.\ngetWidgetLocalToGlobal    : 获取widget在屏幕上的坐标.\ngetImageWH                : 获取图片宽高，加载错误情况返回 Rect.zero.（单位 px）. \ngetImageWHE               : 获取图片宽高，加载错误会抛出异常.（单位 px）. \n\n\u002F\u002F\u002F widget渲染监听。\nWidgetUtil widgetUtil = new WidgetUtil();\nwidgetUtil.asyncPrepare(context, true, (Rect rect) {\n  \u002F\u002F widget渲染完成。\n});\n\n\u002F\u002F\u002F widget宽高。\nRect rect = WidgetUtil.getWidgetBounds(context);\n\n\u002F\u002F\u002F widget在屏幕上的坐标。\nOffset offset = WidgetUtil.getWidgetLocalToGlobal(context);\n  \n\u002F\u002F\u002F 获取CachedNetworkImage下的图片尺寸\nImage image = new Image(image: new CachedNetworkImageProvider(\"Url\"));\nRect rect1 = await WidgetUtil.getImageWH(image: image);  \n\n\u002F\u002F\u002F 其他image\nImage imageAsset = new Image.asset(\"\");\nImage imageFile = new Image.file(File(\"path\"));\nImage imageNetwork = new Image.network(\"url\");\nImage imageMemory = new Image.memory(null);\n\n\u002F\u002F\u002F 获取网络图片尺寸\nRect rect2 = await WidgetUtil.getImageWH(url: \"Url\");\n\n\u002F\u002F\u002F 获取本地图片尺寸 localUrl 需要全路径\nRect rect3 = await WidgetUtil.getImageWH(localUrl: \"assets\u002Fimages\u002F3.0x\u002Fali_connors.png\");\n\n\u002F\u002F\u002F 其他方式\nWidgetUtil.getImageWH(url: \"Url\").then((Rect rect) {\n  print(\"rect: \" + rect.toString();\n});\n\nWidgetUtil.getImageWHE(url: \"Url\").then((Rect rect) {\n  print(\"rect: \" + rect.toString();\n}).catchError((error) {\n  print(\"rect: \" + error.toString();\n});\n```\n\n* #### ImageUtil\n```dart\ngetImageWH\n```\n\n* #### DioUtil (dio: ^1.0.13) 详细请求+解析请参考[flutter_wanandroid][flutter_wanandroid_github]项目。\n```\n\u002F\u002F 打开debug模式.\nDioUtil.openDebug(); \n\n\u002F\u002F 配置网络参数.\nOptions options = DioUtil.getDefOptions();\noptions.baseUrl = \"http:\u002F\u002Fwww.wanandroid.com\u002F\";\nHttpConfig config = new HttpConfig(options: options);\nDioUtil().setConfig(config);\n  \n\u002F\u002F 两种单例请求方式.\nDioUtil().request\u003CList>(Method.get, \"banner\u002Fjson\");\nDioUtil.getInstance().request(Method.get, \"banner\u002Fjson\");\n  \n\u002F\u002F示例\nLoginReq req = new LoginReq('username', 'password');\nDioUtil().request(Method.post, \"user\u002Flogin\",data: req.toJson());\n  \n\u002F\u002F示例\nFormData formData = new FormData.from({\n      \"username\": \"username\",\n      \"password\": \"password\",\n    });\nDioUtil().requestR(Method.post, \"user\u002Flogin\",data: rformData);\n  \n\u002F\u002F 网络请求日志  \nI\u002Fflutter ( 5922): ----------------Http Log----------------\nI\u002Fflutter ( 5922): [statusCode]:   200\nI\u002Fflutter ( 5922): [request   ]:   method: GET  baseUrl: http:\u002F\u002Fwww.wanandroid.com\u002F  path: lg\u002Fcollect\u002Flist\u002F0\u002Fjson\nI\u002Fflutter ( 5922): [reqdata   ]:   null\nI\u002Fflutter ( 5922): [response  ]:   {data: {curPage: 1, datas: [], offset: 0, over: true, pageCount: 0, size: 20, total: 0}, errorCode: 0, errorMsg: }\n```\n\n### 关于作者\nGitHub &nbsp;&nbsp;&nbsp;: [Sky24n](https:\u002F\u002Fgithub.com\u002FSky24n)  \n简书 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: [Sky24n](https:\u002F\u002Fwww.jianshu.com\u002Fu\u002Fcbf2ad25d33a)  \n掘金 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: [Sky24n](https:\u002F\u002Fjuejin.im\u002Fuser\u002F5b9e8a92e51d453df0440422\u002Fposts)  \n项目合集 : [FlutterRepos](https:\u002F\u002Fgithub.com\u002FSky24n\u002FFlutterRepos)\n\n### Changelog\nPlease see the [Changelog](CHANGELOG.md) page to know what's recently changed.\n\n### Apps\n[flutter_wanandroid](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflutter_wanandroid)  \n[Moss](https:\u002F\u002Fgithub.com\u002FSky24n\u002FMoss).  \nA GitHub client app developed with Flutter, which supports Android iOS Web.  \nWeb ：[Flutter Web](https:\u002F\u002Fsky24n.github.io\u002FSky24n\u002Fmoss).\n\n|![](https:\u002F\u002Fz3.ax1x.com\u002F2021\u002F04\u002F26\u002Fgp1hm6.jpg)|![](https:\u002F\u002Fz3.ax1x.com\u002F2021\u002F04\u002F26\u002Fgp1Tte.jpg)|![](https:\u002F\u002Fz3.ax1x.com\u002F2021\u002F04\u002F26\u002Fgp17fH.jpg)|\n|:---:|:---:|:---:|\n\n\n\n[flutter_wanandroid_github]: https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflutter_wanandroid\n\n[common_utils_github]: https:\u002F\u002Fgithub.com\u002FSky24n\u002Fcommon_utils\n\n[flustars_github]: https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflustars\n","flustars 是一个 Flutter 常用工具类库，提供了多种实用的功能以简化开发过程。其核心功能包括 SharedPreferences 工具类 SpUtil、屏幕适配工具 ScreenUtil 以及 Widget 相关操作工具 WidgetUtil 等。这些工具不仅支持基本的数据存储与读取，还能帮助开发者轻松处理屏幕尺寸相关问题及获取控件布局信息。此外，项目还封装了日期时间处理、数字运算、日志打印等多种辅助功能，极大地丰富了其实用性。flustars 适用于需要快速集成常用功能的 Flutter 应用开发场景，特别是那些对 UI 自适应和数据持久化有较高要求的应用程序。",2,"2026-06-11 03:21:58","top_language"]