[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-9124":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":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":17,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":29,"readmeContent":30,"aiSummary":31,"trendingCount":16,"starSnapshotCount":16,"syncStatus":18,"lastSyncTime":32,"discoverSource":33},9124,"flutter_wanandroid","Sky24n\u002Fflutter_wanandroid","Sky24n","🔥🔥🔥  基于Google Flutter的WanAndroid客户端，支持Android和iOS。包括BLoC、RxDart 、国际化、主题色、启动页、引导页！","",null,"Dart",5670,1215,138,13,0,1,2,65.95,"BSD 2-Clause \"Simplified\" License",false,"master",true,[25,26,27,28],"bloc","flutter","rxdart","wanandroid","2026-06-12 04:00:43","# Flutter版 WanAndroid App.\n\n本项目包含启动页，引导页，主题色，国际化，Bloc，RxDart。拥有较好的项目结构，比较规范的代码。 App拥有精致的UI界面，统一的交互，侧滑退出，列表和Web界面均提供快速滚动至顶部功能。  \n\n有关项目最新动态，可以关注App内第一条Hot Item信息。\n\n## [Moss App](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\u002Findex.html).\n\n### 运行本项目注意！！！\n\nSupport [√] Flutter (Channel stable, v1.17.0).  \n\n由于在国内访问Flutter有时可能会受到限制，clone项目后，请勿直接packages get，建议运行如下目录行：\n```\nexport PUB_HOSTED_URL=https:\u002F\u002Fpub.flutter-io.cn  \nexport FLUTTER_STORAGE_BASE_URL=https:\u002F\u002Fstorage.flutter-io.cn  \nflutter packages get\nflutter run --release\n```\n\n### [更新说明](.\u002FCHANGELOGS.md)\nv0.2.6 (2020.05.08)  \nSupport [√] Flutter (Channel stable, v1.17.0).  \n版本升级功能(仅供参考)\n\n### [FlutterRepos](https:\u002F\u002Fgithub.com\u002FSky24n\u002FFlutterRepos)\n1. [base_library](https:\u002F\u002Fgithub.com\u002FSky24n\u002FFlutterRepos\u002Ftree\u002Fmaster\u002Fbase_library) Flutter基础组件库，方便多个项目共用。\n2. [login_demo](https:\u002F\u002Fgithub.com\u002FSky24n\u002FFlutterRepos\u002Ftree\u002Fmaster\u002Flogin_demo) 关于App启动时，未登录跳登录页，已登录进主页。\n3. [flutter_gallery](https:\u002F\u002Fgithub.com\u002FSky24n\u002FFlutterRepos\u002Ftree\u002Fmaster\u002Fflutter_gallery) 也许是Google官方最后一个版本的gallery(旧版)。\n\n### App目录结构\n>- |--lib\n>    - |-- blocs (bloc相关)\n>    - |-- common (常用类，例如常量Constant)\n>    - |-- data (网络数据层)\n>    - |-- db (数据库)\n>    - |-- demos (flutter demos)\n>    - |-- event (事件类)\n>    - |-- models (实体类)\n>    - |-- res (资源文件，string，colors，dimens，styles)\n>    - |-- ui (界面相关page，dialog，widgets)\n>    - |-- utils (工具类)\n\n### data网络数据层\n>- |--data\n>    - |-- api (url字段)\n>    - |-- net (单例DioUtil)\n>    - |-- protocol (请求与返回实体类)\n>    - |-- repository (接口请求&解析)\n\n### api\n```dart\nclass WanAndroidApi {\n  \u002F\u002F\u002F 首页banner http:\u002F\u002Fwww.wanandroid.com\u002Fbanner\u002Fjson\n  static const String BANNER = \"banner\";\n  static const String USER_REGISTER = \"user\u002Fregister\"; \u002F\u002F注册\n  static const String USER_LOGIN = \"user\u002Flogin\"; \u002F\u002F登录\n  static const String USER_LOGOUT = \"user\u002Flogout\"; \u002F\u002F退出\n\n  \u002F\u002F 拼接url\n  static String getPath({String path: '', int page, String resType: 'json'}) {\n    StringBuffer sb = new StringBuffer(path);\n    if (page != null) {\n      sb.write('\u002F$page');\n    }\n    if (resType != null && resType.isNotEmpty) {\n      sb.write('\u002F$resType');\n    }\n    return sb.toString();\n  }\n}\n```\n### 网络请求工具类 DioUtil\n```dart\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```  \n### 请求与返回实体类 protocol\n```dart\nclass LoginReq {\n  String username;\n  String password;\n\n  LoginReq(this.username, this.password);\n\n  LoginReq.fromJson(Map\u003CString, dynamic> json)\n      : username = json['username'],\n        password = json['password'];\n\n  Map\u003CString, dynamic> toJson() => {\n    'username': username,\n    'password': password,\n  };\n\n  @override\n  String toString() {\n    StringBuffer sb = new StringBuffer('{');\n    sb.write(\"\\\"username\\\":\\\"$username\\\"\");\n    sb.write(\",\\\"password\\\":$password\");\n    sb.write('}');\n    return sb.toString();\n  }\n}\n```\n### 接口请求&解析 repository\n```dart\n class WanRepository {\n  Future\u003CList\u003CBannerModel>> getBanner() async {\n    BaseResp\u003CList> baseResp = await DioUtil().request\u003CList>(\n        Method.get, WanAndroidApi.getPath(path: WanAndroidApi.BANNER));\n    List\u003CBannerModel> bannerList;\n    if (baseResp.code != Constant.STATUS_SUCCESS) {\n      return new Future.error(baseResp.msg);\n    }\n    if (baseResp.data != null) {\n      bannerList = baseResp.data.map((value) {\n        return BannerModel.fromJson(value);\n      }).toList();\n    }\n    return bannerList;\n  }\n}\n```\n\n### 资源文件 res\n>- |--res\n>    - |-- colors.dart\n>    - |-- dimens.dart\n>    - |-- strings.dart\n>    - |-- styles.dart\n\n### colors.dart\n```dart\nclass Colours {\n  static const Color app_main = Color(0xFF666666);  \n  \n  static const Color text_dark = Color(0xFF333333);\n  static const Color text_normal = Color(0xFF666666);\n  static const Color text_gray = Color(0xFF999999);  \n}\n```\n### dimens.dart\n```dart\nclass Dimens {\n  static const double font_sp12 = 12;\n  static const double font_sp14 = 14;\n  static const double font_sp16 = 16;\n  \n  static const double gap_dp5 = 5;\n  static const double gap_dp10 = 10;\n}\n```\n### strings.dart\n```dart\nclass Ids {\n  static const String titleHome = 'title_home';\n}  \nMap\u003CString, Map\u003CString, Map\u003CString, String>>> localizedValues = {\n  'en': {\n    'US': {\n      Ids.titleHome: 'Home',\n    }\n  },\n  'zh': {\n    'CN': {\n      Ids.titleHome: '主页',\n    },\n    'HK': {\n      Ids.titleHome: '主頁',\n    },\n    'TW': {\n      Ids.titleHome: '主頁',\n    }\n  }\n};\n```\n### styles.dart\n```dart\nclass TextStyles {\n  static TextStyle listTitle = TextStyle(\n    fontSize: Dimens.font_sp16,\n    color: Colours.text_dark,\n    fontWeight: FontWeight.bold,\n  );\n  static TextStyle listContent = TextStyle(\n    fontSize: Dimens.font_sp14,\n    color: Colours.text_normal,\n  );\n  static TextStyle listExtra = TextStyle(\n    fontSize: Dimens.font_sp12,\n    color: Colours.text_gray,\n  );\n}\n\u002F\u002F  间隔\nclass Gaps {\n  \u002F\u002F 水平间隔\n  static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5);\n  static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10);\n  \u002F\u002F 垂直间隔\n  static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5);\n  static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10);\n}\n```\n### Flutter 国际化相关 [fluintl](https:\u002F\u002Fgithub.com\u002FSky24n\u002Ffluintl)\nfluintl是一个为应用提供国际化的库，可快速集成实现应用多语言。该库封装了一个国际化支持类，通过提供统一方法getString(id)获取字符串。\n```dart\n\u002F\u002F 在MyApp initState配置多语言资源\nsetLocalizedValues(localizedValues); \u002F\u002F配置多语言资源\n\u002F\u002F 在MaterialApp指定localizationsDelegates和supportedLocales\nMaterialApp(  \n   home: MyHomePage(),  \n   localizationsDelegates: [  \n   GlobalMaterialLocalizations.delegate,  \n   GlobalWidgetsLocalizations.delegate,  \n   CustomLocalizations.delegate \u002F\u002F设置本地化代理     \n   ],  \n   supportedLocales: CustomLocalizations.supportedLocales,\u002F\u002F设置支持本地化语言集合     \n); \n\u002F\u002F 字符串获取\nIntlUtil.getString(context, Ids.titleHome);\nCustomLocalizations.of(context).getString(StringIds.titleHome);  \n\n\u002F\u002F 支持复用。替换字符串格式要求：'%\\${index}\\$s' ，{index} 第几个参数，从0开始。\nIds.click_times: '%\\$0\\$s点击了%\\$1\\$s次',   \nIntlUtil.getString(context, Ids.click_times, params: ['Tom', '$_counter'])  \n\u002F\u002F print: Tom点击了0次\n```\n\n### Flutter 屏幕适配 [ScreenUtil](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflustars) \n 方案一、不依赖context\n```dart\n\u002F\u002F 步骤1\n\u002F\u002F 如果设计稿尺寸默认配置一致，无需该设置。  配置设计稿尺寸 默认 360.0 \u002F 640.0 \u002F 3.0\nsetDesignWHD(_designW,_designH,_designD);  \n  \n\u002F\u002F 步骤2\n\u002F\u002F 在MainPageState build 调用MediaQuery.of(context)\nclass MainPageState extends State\u003CMainPage> {\n  @override\n  Widget build(BuildContext context) {\n    \u002F\u002F 在 MainPageState build 调用 MediaQuery.of(context)\n    MediaQuery.of(context);\n    return new Scaffold(\n      appBar: new AppBar(),\n    );\n  }\n}  \n  \n\u002F\u002F 步骤3\nScreenUtil.getInstance().screenWidth\nScreenUtil.getInstance().screenHeight\n\u002F\u002F屏幕适配相关  \nScreenUtil.getInstance().getWidth(size); \u002F\u002F返回根据屏幕宽适配后尺寸（单位 dp or pt）\nScreenUtil.getInstance().getHeight(size); \u002F\u002F返回根据屏幕高适配后尺寸 （单位 dp or pt）\nScreenUtil.getInstance().getWidthPx(sizePx); \u002F\u002FsizePx 单位px\nScreenUtil.getInstance().getHeightPx(sizePx); \u002F\u002FsizePx 单位px\nScreenUtil.getInstance().getSp(fontSize); \u002F\u002F返回根据屏幕宽适配后字体尺寸\n  \ndouble adapterSize = ScreenUtil.getInstance().getAdapterSize(100);\n```\n方案二、依赖context\n```dart\n\u002F\u002F如果设计稿尺寸默认配置一致，无需该设置。  配置设计稿尺寸 默认 360.0 \u002F 640.0 \u002F 3.0\nsetDesignWHD(_designW,_designH,_designD);  \n\nScreenUtil.getScreenW(context); \u002F\u002F屏幕 宽\nScreenUtil.getScreenH(context); \u002F\u002F屏幕 高\n\u002F\u002F屏幕适配相关  \nScreenUtil.getScaleW(context, size); \u002F\u002F返回根据屏幕宽适配后尺寸（单位 dp or pt）\nScreenUtil.getScaleH(context, size); \u002F\u002F返回根据屏幕高适配后尺寸 （单位 dp or pt）\nScreenUtil.getScaleSp(context, size) ;\u002F\u002F返回根据屏幕宽适配后字体尺寸\n  \ndouble adapterSize = ScreenUtil.getAdapterSizeCtx(context, 100)\n```\n### Flutter 数据存储  [SpUtil](https:\u002F\u002Fgithub.com\u002FSky24n\u002Fflustars)\n单例\"同步\" SharedPreferences 工具类。  \n支持get获取默认参数、支持存储实体对象、支持存储实体对象数组。\n```dart\n    \u002F\u002F 等待Sp初始化完成。\n    await SpUtil.getInstance();\n    \n    SpUtil.getString('key', defValue: '');\n    SpUtil.getInt('key', defValue: 0);\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(\"thll Str: \" + (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(\"thll List: \" + (_cityList == null ? \"null\" : _cityList.toString()));\n```\n\n### Flutter Demos \n>- |--demos\n>    - |-- city_select_page.dart 城市列表(索引&悬停)示例\n>    - |-- date_page.dart 日期格式化示例\n>    - |-- image_size_page.dart 获取图片尺寸示例\n>    - |-- money_page.dart 金额(元转分\u002F分转元)示例\n>    - |-- pinyin_page.dart 汉字转拼音示例\n>    - |-- regex_page.dart 正则工具类示例\n>    - |-- round_portrait_page.dart 圆形圆角头像示例\n>    - |-- timeline_page.dart 时间轴示例\n>    - |-- timer_page.dart 倒计时\u002F定时任务示例\n>    - |-- widget_page.dart 获取Widget尺寸\u002F屏幕坐标示例\n\n\n### Screenshots\n\n截图无法查看？\n\n[掘金地址](https:\u002F\u002Fjuejin.im\u002Fpost\u002F5c380b336fb9a049fd100eff)  \n[简书地址](https:\u002F\u002Fwww.jianshu.com\u002Fp\u002Fbe0107298bc5)\n\n|主界面|启动页|侧滑Back|\n|:---:|:---:|:---:|\n|![](https:\u002F\u002Fgitee.com\u002Fuploads\u002Fimages\u002F2019\u002F0506\u002F004903_0837c169_506864.gif)|![](https:\u002F\u002Fraw.githubusercontent.com\u002FSky24n\u002FLDocuments\u002Fmaster\u002FAppImgs\u002Fflutter_wanandroid\u002Fsplash.gif\")|![](https:\u002F\u002Fraw.githubusercontent.com\u002FSky24n\u002FLDocuments\u002Fmaster\u002FAppImgs\u002Fflutter_wanandroid\u002Fslide_back.gif\")|\n|快速滚动到顶部|分类页面|国际化|\n|![](https:\u002F\u002Fgitee.com\u002Fuploads\u002Fimages\u002F2019\u002F0506\u002F004903_0837c169_506864.gif\")|![](https:\u002F\u002Fraw.githubusercontent.com\u002FSky24n\u002FLDocuments\u002Fmaster\u002FAppImgs\u002Fflutter_wanandroid\u002Ftree.gif\")|![](https:\u002F\u002Fgitee.com\u002Fuploads\u002Fimages\u002F2019\u002F0506\u002F004906_f1f1147e_506864.gif\")|\n|主题色|闪屏广告页|引导页|\n|![](https:\u002F\u002Fgitee.com\u002Fuploads\u002Fimages\u002F2019\u002F0506\u002F004907_498b0fb8_506864.gif\")|![](https:\u002F\u002Fraw.githubusercontent.com\u002FSky24n\u002FLDocuments\u002Fmaster\u002FAppImgs\u002Fflutter_wanandroid\u002F2018-11-23_13_05_08.gif\")|![](https:\u002F\u002Fraw.githubusercontent.com\u002FSky24n\u002FLDocuments\u002Fmaster\u002FAppImgs\u002Fflutter_wanandroid\u002F2018-11-19_12_35_32.gif\")|\n\n### Thanks\n① 感谢鸿洋大佬提供的[开源api](http:\u002F\u002Fwww.wanandroid.com\u002Fblog\u002Fshow\u002F2)  \n② 界面参考[gitme](https:\u002F\u002Fflutterchina.club\u002Fapp\u002Fgm.html)  \n③ [Github Trending Api](https:\u002F\u002Fgithub.com\u002Fhuchenme\u002Fgithub-trending-api)   \n④ [Streams-Block-Reactive-Programming-in-Flutter](https:\u002F\u002Fgithub.com\u002Fboeledi\u002FStreams-Block-Reactive-Programming-in-Flutter) \n\n### 项目问题汇总\nQ1：Flutter国际化系统切换iOS不生效问题？  \nA1：在Xcode项目Localizations下添加支持语言即可，[原文](https:\u002F\u002Fstanzhai.site\u002Fblog\u002Fpost\u002Fstanzhai\u002FFlutter国际化设置在iOS设备上不生效的问题)。\n\n### App\nApk：[flutter_wanandroid.apk](https:\u002F\u002Fgithub.com\u002FSky24n\u002FDoc)  \niOS：请自行clone项目代码运行。\n\n### 关于作者\nGitHub : [Sky24n](https:\u002F\u002Fgithub.com\u002FSky24n)  \n简书 &nbsp;&nbsp;&nbsp;&nbsp;: [Sky24n](https:\u002F\u002Fwww.jianshu.com\u002Fu\u002Fcbf2ad25d33a)  \n掘金 &nbsp;&nbsp;&nbsp;&nbsp;: [Sky24n](https:\u002F\u002Fjuejin.im\u002Fuser\u002F5b9e8a92e51d453df0440422\u002Fposts)  \nEmail &nbsp;&nbsp;: 863764940@qq.com\n\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","该项目是一个基于Google Flutter框架构建的WanAndroid客户端应用，支持Android和iOS双平台。它集成了BLoC状态管理和RxDart响应式编程库，实现了国际化、自定义主题色等功能，并提供了启动页与引导页等用户体验优化设计。项目结构清晰规范，代码质量高，具有良好的UI界面及统一的交互体验，如侧滑退出和快速滚动至顶部功能。适用于需要跨平台开发且追求高质量用户体验的应用场景，特别是对于那些希望学习或参考如何使用Flutter结合现代前端架构模式来构建复杂应用的开发者来说，这是一个非常有价值的案例。","2026-06-11 03:21:19","top_language"]