{"id":14956356,"url":"https://github.com/sky24n/flutter_wanandroid","last_synced_at":"2025-05-14T17:09:22.680Z","repository":{"id":37923688,"uuid":"150520914","full_name":"Sky24n/flutter_wanandroid","owner":"Sky24n","description":"🔥🔥🔥  基于Google Flutter的WanAndroid客户端，支持Android和iOS。包括BLoC、RxDart 、国际化、主题色、启动页、引导页！","archived":false,"fork":false,"pushed_at":"2021-05-21T08:53:02.000Z","size":2090,"stargazers_count":5659,"open_issues_count":13,"forks_count":1232,"subscribers_count":139,"default_branch":"master","last_synced_at":"2025-05-14T17:08:39.893Z","etag":null,"topics":["bloc","flutter","rxdart","wanandroid"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sky24n.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://sky24n.github.io/Sky24n/image/ali_pay.jpg","https://sky24n.github.io/Sky24n/image/wechat_pay.jpg"]}},"created_at":"2018-09-27T03:02:39.000Z","updated_at":"2025-05-10T04:02:24.000Z","dependencies_parsed_at":"2022-07-12T17:03:26.337Z","dependency_job_id":null,"html_url":"https://github.com/Sky24n/flutter_wanandroid","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sky24n%2Fflutter_wanandroid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sky24n%2Fflutter_wanandroid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sky24n%2Fflutter_wanandroid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sky24n%2Fflutter_wanandroid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sky24n","download_url":"https://codeload.github.com/Sky24n/flutter_wanandroid/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254190396,"owners_count":22029632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bloc","flutter","rxdart","wanandroid"],"created_at":"2024-09-24T13:12:52.194Z","updated_at":"2025-05-14T17:09:22.661Z","avatar_url":"https://github.com/Sky24n.png","language":"Dart","readme":"# Flutter版 WanAndroid App.\n\n本项目包含启动页，引导页，主题色，国际化，Bloc，RxDart。拥有较好的项目结构，比较规范的代码。 App拥有精致的UI界面，统一的交互，侧滑退出，列表和Web界面均提供快速滚动至顶部功能。  \n\n有关项目最新动态，可以关注App内第一条Hot Item信息。\n\n## [Moss App](https://github.com/Sky24n/Moss)\nA GitHub client app developed with Flutter, which supports Android iOS Web.  \nWeb ：[Flutter Web](https://sky24n.github.io/Sky24n/moss/index.html).\n\n### 运行本项目注意！！！\n\nSupport [√] Flutter (Channel stable, v1.17.0).  \n\n由于在国内访问Flutter有时可能会受到限制，clone项目后，请勿直接packages get，建议运行如下目录行：\n```\nexport PUB_HOSTED_URL=https://pub.flutter-io.cn  \nexport FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn  \nflutter packages get\nflutter run --release\n```\n\n### [更新说明](./CHANGELOGS.md)\nv0.2.6 (2020.05.08)  \nSupport [√] Flutter (Channel stable, v1.17.0).  \n版本升级功能(仅供参考)\n\n### [FlutterRepos](https://github.com/Sky24n/FlutterRepos)\n1. [base_library](https://github.com/Sky24n/FlutterRepos/tree/master/base_library) Flutter基础组件库，方便多个项目共用。\n2. [login_demo](https://github.com/Sky24n/FlutterRepos/tree/master/login_demo) 关于App启动时，未登录跳登录页，已登录进主页。\n3. [flutter_gallery](https://github.com/Sky24n/FlutterRepos/tree/master/flutter_gallery) 也许是Google官方最后一个版本的gallery(旧版)。\n\n### App目录结构\n\u003e- |--lib\n\u003e    - |-- blocs (bloc相关)\n\u003e    - |-- common (常用类，例如常量Constant)\n\u003e    - |-- data (网络数据层)\n\u003e    - |-- db (数据库)\n\u003e    - |-- demos (flutter demos)\n\u003e    - |-- event (事件类)\n\u003e    - |-- models (实体类)\n\u003e    - |-- res (资源文件，string，colors，dimens，styles)\n\u003e    - |-- ui (界面相关page，dialog，widgets)\n\u003e    - |-- utils (工具类)\n\n### data网络数据层\n\u003e- |--data\n\u003e    - |-- api (url字段)\n\u003e    - |-- net (单例DioUtil)\n\u003e    - |-- protocol (请求与返回实体类)\n\u003e    - |-- repository (接口请求\u0026解析)\n\n### api\n```dart\nclass WanAndroidApi {\n  /// 首页banner http://www.wanandroid.com/banner/json\n  static const String BANNER = \"banner\";\n  static const String USER_REGISTER = \"user/register\"; //注册\n  static const String USER_LOGIN = \"user/login\"; //登录\n  static const String USER_LOGOUT = \"user/logout\"; //退出\n\n  // 拼接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('/$page');\n    }\n    if (resType != null \u0026\u0026 resType.isNotEmpty) {\n      sb.write('/$resType');\n    }\n    return sb.toString();\n  }\n}\n```\n### 网络请求工具类 DioUtil\n```dart\n// 打开debug模式.\nDioUtil.openDebug();   \n  \n// 配置网络参数.\nOptions options = DioUtil.getDefOptions();\noptions.baseUrl = \"http://www.wanandroid.com/\";\nHttpConfig config = new HttpConfig(options: options);\nDioUtil().setConfig(config);\n  \n// 两种单例请求方式.\nDioUtil().request\u003cList\u003e(Method.get, \"banner/json\");\nDioUtil.getInstance().request(Method.get, \"banner/json\");\n  \n//示例\nLoginReq req = new LoginReq('username', 'password');\nDioUtil().request(Method.post, \"user/login\",data: req.toJson());\n  \n//示例\nFormData formData = new FormData.from({\n      \"username\": \"username\",\n      \"password\": \"password\",\n    });\nDioUtil().requestR(Method.post, \"user/login\",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\u003e json)\n      : username = json['username'],\n        password = json['password'];\n\n  Map\u003cString, dynamic\u003e toJson() =\u003e {\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### 接口请求\u0026解析 repository\n```dart\n class WanRepository {\n  Future\u003cList\u003cBannerModel\u003e\u003e getBanner() async {\n    BaseResp\u003cList\u003e baseResp = await DioUtil().request\u003cList\u003e(\n        Method.get, WanAndroidApi.getPath(path: WanAndroidApi.BANNER));\n    List\u003cBannerModel\u003e 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\u003e- |--res\n\u003e    - |-- colors.dart\n\u003e    - |-- dimens.dart\n\u003e    - |-- strings.dart\n\u003e    - |-- 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\u003e\u003e\u003e 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//  间隔\nclass Gaps {\n  // 水平间隔\n  static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5);\n  static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10);\n  // 垂直间隔\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://github.com/Sky24n/fluintl)\nfluintl是一个为应用提供国际化的库，可快速集成实现应用多语言。该库封装了一个国际化支持类，通过提供统一方法getString(id)获取字符串。\n```dart\n// 在MyApp initState配置多语言资源\nsetLocalizedValues(localizedValues); //配置多语言资源\n// 在MaterialApp指定localizationsDelegates和supportedLocales\nMaterialApp(  \n   home: MyHomePage(),  \n   localizationsDelegates: [  \n   GlobalMaterialLocalizations.delegate,  \n   GlobalWidgetsLocalizations.delegate,  \n   CustomLocalizations.delegate //设置本地化代理     \n   ],  \n   supportedLocales: CustomLocalizations.supportedLocales,//设置支持本地化语言集合     \n); \n// 字符串获取\nIntlUtil.getString(context, Ids.titleHome);\nCustomLocalizations.of(context).getString(StringIds.titleHome);  \n\n// 支持复用。替换字符串格式要求：'%\\${index}\\$s' ，{index} 第几个参数，从0开始。\nIds.click_times: '%\\$0\\$s点击了%\\$1\\$s次',   \nIntlUtil.getString(context, Ids.click_times, params: ['Tom', '$_counter'])  \n// print: Tom点击了0次\n```\n\n### Flutter 屏幕适配 [ScreenUtil](https://github.com/Sky24n/flustars) \n 方案一、不依赖context\n```dart\n// 步骤1\n// 如果设计稿尺寸默认配置一致，无需该设置。  配置设计稿尺寸 默认 360.0 / 640.0 / 3.0\nsetDesignWHD(_designW,_designH,_designD);  \n  \n// 步骤2\n// 在MainPageState build 调用MediaQuery.of(context)\nclass MainPageState extends State\u003cMainPage\u003e {\n  @override\n  Widget build(BuildContext context) {\n    // 在 MainPageState build 调用 MediaQuery.of(context)\n    MediaQuery.of(context);\n    return new Scaffold(\n      appBar: new AppBar(),\n    );\n  }\n}  \n  \n// 步骤3\nScreenUtil.getInstance().screenWidth\nScreenUtil.getInstance().screenHeight\n//屏幕适配相关  \nScreenUtil.getInstance().getWidth(size); //返回根据屏幕宽适配后尺寸（单位 dp or pt）\nScreenUtil.getInstance().getHeight(size); //返回根据屏幕高适配后尺寸 （单位 dp or pt）\nScreenUtil.getInstance().getWidthPx(sizePx); //sizePx 单位px\nScreenUtil.getInstance().getHeightPx(sizePx); //sizePx 单位px\nScreenUtil.getInstance().getSp(fontSize); //返回根据屏幕宽适配后字体尺寸\n  \ndouble adapterSize = ScreenUtil.getInstance().getAdapterSize(100);\n```\n方案二、依赖context\n```dart\n//如果设计稿尺寸默认配置一致，无需该设置。  配置设计稿尺寸 默认 360.0 / 640.0 / 3.0\nsetDesignWHD(_designW,_designH,_designD);  \n\nScreenUtil.getScreenW(context); //屏幕 宽\nScreenUtil.getScreenH(context); //屏幕 高\n//屏幕适配相关  \nScreenUtil.getScaleW(context, size); //返回根据屏幕宽适配后尺寸（单位 dp or pt）\nScreenUtil.getScaleH(context, size); //返回根据屏幕高适配后尺寸 （单位 dp or pt）\nScreenUtil.getScaleSp(context, size) ;//返回根据屏幕宽适配后字体尺寸\n  \ndouble adapterSize = ScreenUtil.getAdapterSizeCtx(context, 100)\n```\n### Flutter 数据存储  [SpUtil](https://github.com/Sky24n/flustars)\n单例\"同步\" SharedPreferences 工具类。  \n支持get获取默认参数、支持存储实体对象、支持存储实体对象数组。\n```dart\n    // 等待Sp初始化完成。\n    await SpUtil.getInstance();\n    \n    SpUtil.getString('key', defValue: '');\n    SpUtil.getInt('key', defValue: 0);\n  \n    /// save object example.\n    /// 存储实体对象示例。\n    City city = new City();\n    city.name = \"成都市\";\n    SpUtil.putObject(\"loc_city\", city);\n  \n    City hisCity = SpUtil.getObj(\"loc_city\", (v) =\u003e City.fromJson(v)); \n    print(\"thll Str: \" + (hisCity == null ? \"null\" : hisCity.toString()));\n  \n    /// save object list example.\n    /// 存储实体对象List示例。\n    List\u003cCity\u003e 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\u003e _cityList = SpUtil.getObjList(\"loc_city_list\", (v) =\u003e City.fromJson(v));\n    print(\"thll List: \" + (_cityList == null ? \"null\" : _cityList.toString()));\n```\n\n### Flutter Demos \n\u003e- |--demos\n\u003e    - |-- city_select_page.dart 城市列表(索引\u0026悬停)示例\n\u003e    - |-- date_page.dart 日期格式化示例\n\u003e    - |-- image_size_page.dart 获取图片尺寸示例\n\u003e    - |-- money_page.dart 金额(元转分/分转元)示例\n\u003e    - |-- pinyin_page.dart 汉字转拼音示例\n\u003e    - |-- regex_page.dart 正则工具类示例\n\u003e    - |-- round_portrait_page.dart 圆形圆角头像示例\n\u003e    - |-- timeline_page.dart 时间轴示例\n\u003e    - |-- timer_page.dart 倒计时/定时任务示例\n\u003e    - |-- widget_page.dart 获取Widget尺寸/屏幕坐标示例\n\n\n### Screenshots\n\n截图无法查看？\n\n[掘金地址](https://juejin.im/post/5c380b336fb9a049fd100eff)  \n[简书地址](https://www.jianshu.com/p/be0107298bc5)\n\n|主界面|启动页|侧滑Back|\n|:---:|:---:|:---:|\n|![](https://gitee.com/uploads/images/2019/0506/004903_0837c169_506864.gif)|![](https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_wanandroid/splash.gif\")|![](https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_wanandroid/slide_back.gif\")|\n|快速滚动到顶部|分类页面|国际化|\n|![](https://gitee.com/uploads/images/2019/0506/004903_0837c169_506864.gif\")|![](https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_wanandroid/tree.gif\")|![](https://gitee.com/uploads/images/2019/0506/004906_f1f1147e_506864.gif\")|\n|主题色|闪屏广告页|引导页|\n|![](https://gitee.com/uploads/images/2019/0506/004907_498b0fb8_506864.gif\")|![](https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_wanandroid/2018-11-23_13_05_08.gif\")|![](https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_wanandroid/2018-11-19_12_35_32.gif\")|\n\n### Thanks\n① 感谢鸿洋大佬提供的[开源api](http://www.wanandroid.com/blog/show/2)  \n② 界面参考[gitme](https://flutterchina.club/app/gm.html)  \n③ [Github Trending Api](https://github.com/huchenme/github-trending-api)   \n④ [Streams-Block-Reactive-Programming-in-Flutter](https://github.com/boeledi/Streams-Block-Reactive-Programming-in-Flutter) \n\n### 项目问题汇总\nQ1：Flutter国际化系统切换iOS不生效问题？  \nA1：在Xcode项目Localizations下添加支持语言即可，[原文](https://stanzhai.site/blog/post/stanzhai/Flutter国际化设置在iOS设备上不生效的问题)。\n\n### App\nApk：[flutter_wanandroid.apk](https://github.com/Sky24n/Doc)  \niOS：请自行clone项目代码运行。\n\n### 关于作者\nGitHub : [Sky24n](https://github.com/Sky24n)  \n简书 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;: [Sky24n](https://www.jianshu.com/u/cbf2ad25d33a)  \n掘金 \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;: [Sky24n](https://juejin.im/user/5b9e8a92e51d453df0440422/posts)  \nEmail \u0026nbsp;\u0026nbsp;: 863764940@qq.com\n\n### [Moss](https://github.com/Sky24n/Moss)\nA GitHub client app developed with Flutter, which supports Android iOS Web.  \nWeb ：[Flutter Web](https://sky24n.github.io/Sky24n/moss).\n\n|![](https://z3.ax1x.com/2021/04/26/gp1hm6.jpg)|![](https://z3.ax1x.com/2021/04/26/gp1Tte.jpg)|![](https://z3.ax1x.com/2021/04/26/gp17fH.jpg)|\n|:---:|:---:|:---:|\n","funding_links":["https://sky24n.github.io/Sky24n/image/ali_pay.jpg","https://sky24n.github.io/Sky24n/image/wechat_pay.jpg"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsky24n%2Fflutter_wanandroid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsky24n%2Fflutter_wanandroid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsky24n%2Fflutter_wanandroid/lists"}