Skip to content

🔥🔥🔥 基于Google Flutter的WanAndroid客户端,支持Android和iOS。包括BLoC、RxDart 、国际化、主题色、启动页、引导页!

License

Notifications You must be signed in to change notification settings

Sky24n/flutter_wanandroid

Repository files navigation

Flutter版 WanAndroid App.

本项目包含启动页,引导页,主题色,国际化,Bloc,RxDart。拥有较好的项目结构,比较规范的代码。 App拥有精致的UI界面,统一的交互,侧滑退出,列表和Web界面均提供快速滚动至顶部功能。

有关项目最新动态,可以关注App内第一条Hot Item信息。

A GitHub client app developed with Flutter, which supports Android iOS Web.
Web :Flutter Web.

运行本项目注意!!!

Support [√] Flutter (Channel stable, v1.17.0).

由于在国内访问Flutter有时可能会受到限制,clone项目后,请勿直接packages get,建议运行如下目录行:

export PUB_HOSTED_URL=https://pub.flutter-io.cn  
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn  
flutter packages get
flutter run --release

v0.2.6 (2020.05.08)
Support [√] Flutter (Channel stable, v1.17.0).
版本升级功能(仅供参考)

  1. base_library Flutter基础组件库,方便多个项目共用。
  2. login_demo 关于App启动时,未登录跳登录页,已登录进主页。
  3. flutter_gallery 也许是Google官方最后一个版本的gallery(旧版)。

App目录结构

  • |--lib
    • |-- blocs (bloc相关)
    • |-- common (常用类,例如常量Constant)
    • |-- data (网络数据层)
    • |-- db (数据库)
    • |-- demos (flutter demos)
    • |-- event (事件类)
    • |-- models (实体类)
    • |-- res (资源文件,string,colors,dimens,styles)
    • |-- ui (界面相关page,dialog,widgets)
    • |-- utils (工具类)

data网络数据层

  • |--data
    • |-- api (url字段)
    • |-- net (单例DioUtil)
    • |-- protocol (请求与返回实体类)
    • |-- repository (接口请求&解析)

api

class WanAndroidApi {
  /// 首页banner http://www.wanandroid.com/banner/json
  static const String BANNER = "banner";
  static const String USER_REGISTER = "user/register"; //注册
  static const String USER_LOGIN = "user/login"; //登录
  static const String USER_LOGOUT = "user/logout"; //退出

  // 拼接url
  static String getPath({String path: '', int page, String resType: 'json'}) {
    StringBuffer sb = new StringBuffer(path);
    if (page != null) {
      sb.write('/$page');
    }
    if (resType != null && resType.isNotEmpty) {
      sb.write('/$resType');
    }
    return sb.toString();
  }
}

网络请求工具类 DioUtil

// 打开debug模式.
DioUtil.openDebug();   
  
// 配置网络参数.
Options options = DioUtil.getDefOptions();
options.baseUrl = "http://www.wanandroid.com/";
HttpConfig config = new HttpConfig(options: options);
DioUtil().setConfig(config);
  
// 两种单例请求方式.
DioUtil().request<List>(Method.get, "banner/json");
DioUtil.getInstance().request(Method.get, "banner/json");
  
//示例
LoginReq req = new LoginReq('username', 'password');
DioUtil().request(Method.post, "user/login",data: req.toJson());
  
//示例
FormData formData = new FormData.from({
      "username": "username",
      "password": "password",
    });
DioUtil().requestR(Method.post, "user/login",data: rformData);

请求与返回实体类 protocol

class LoginReq {
  String username;
  String password;

  LoginReq(this.username, this.password);

  LoginReq.fromJson(Map<String, dynamic> json)
      : username = json['username'],
        password = json['password'];

  Map<String, dynamic> toJson() => {
    'username': username,
    'password': password,
  };

  @override
  String toString() {
    StringBuffer sb = new StringBuffer('{');
    sb.write("\"username\":\"$username\"");
    sb.write(",\"password\":$password");
    sb.write('}');
    return sb.toString();
  }
}

接口请求&解析 repository

 class WanRepository {
  Future<List<BannerModel>> getBanner() async {
    BaseResp<List> baseResp = await DioUtil().request<List>(
        Method.get, WanAndroidApi.getPath(path: WanAndroidApi.BANNER));
    List<BannerModel> bannerList;
    if (baseResp.code != Constant.STATUS_SUCCESS) {
      return new Future.error(baseResp.msg);
    }
    if (baseResp.data != null) {
      bannerList = baseResp.data.map((value) {
        return BannerModel.fromJson(value);
      }).toList();
    }
    return bannerList;
  }
}

资源文件 res

  • |--res
    • |-- colors.dart
    • |-- dimens.dart
    • |-- strings.dart
    • |-- styles.dart

colors.dart

class Colours {
  static const Color app_main = Color(0xFF666666);  
  
  static const Color text_dark = Color(0xFF333333);
  static const Color text_normal = Color(0xFF666666);
  static const Color text_gray = Color(0xFF999999);  
}

dimens.dart

class Dimens {
  static const double font_sp12 = 12;
  static const double font_sp14 = 14;
  static const double font_sp16 = 16;
  
  static const double gap_dp5 = 5;
  static const double gap_dp10 = 10;
}

strings.dart

class Ids {
  static const String titleHome = 'title_home';
}  
Map<String, Map<String, Map<String, String>>> localizedValues = {
  'en': {
    'US': {
      Ids.titleHome: 'Home',
    }
  },
  'zh': {
    'CN': {
      Ids.titleHome: '主页',
    },
    'HK': {
      Ids.titleHome: '主頁',
    },
    'TW': {
      Ids.titleHome: '主頁',
    }
  }
};

styles.dart

class TextStyles {
  static TextStyle listTitle = TextStyle(
    fontSize: Dimens.font_sp16,
    color: Colours.text_dark,
    fontWeight: FontWeight.bold,
  );
  static TextStyle listContent = TextStyle(
    fontSize: Dimens.font_sp14,
    color: Colours.text_normal,
  );
  static TextStyle listExtra = TextStyle(
    fontSize: Dimens.font_sp12,
    color: Colours.text_gray,
  );
}
//  间隔
class Gaps {
  // 水平间隔
  static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5);
  static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10);
  // 垂直间隔
  static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5);
  static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10);
}

Flutter 国际化相关 fluintl

fluintl是一个为应用提供国际化的库,可快速集成实现应用多语言。该库封装了一个国际化支持类,通过提供统一方法getString(id)获取字符串。

// 在MyApp initState配置多语言资源
setLocalizedValues(localizedValues); //配置多语言资源
// 在MaterialApp指定localizationsDelegates和supportedLocales
MaterialApp(  
   home: MyHomePage(),  
   localizationsDelegates: [  
   GlobalMaterialLocalizations.delegate,  
   GlobalWidgetsLocalizations.delegate,  
   CustomLocalizations.delegate //设置本地化代理     
   ],  
   supportedLocales: CustomLocalizations.supportedLocales,//设置支持本地化语言集合     
); 
// 字符串获取
IntlUtil.getString(context, Ids.titleHome);
CustomLocalizations.of(context).getString(StringIds.titleHome);  

// 支持复用。替换字符串格式要求:'%\${index}\$s' ,{index} 第几个参数,从0开始。
Ids.click_times: '%\$0\$s点击了%\$1\$s次',   
IntlUtil.getString(context, Ids.click_times, params: ['Tom', '$_counter'])  
// print: Tom点击了0次

Flutter 屏幕适配 ScreenUtil

方案一、不依赖context

// 步骤1
// 如果设计稿尺寸默认配置一致,无需该设置。  配置设计稿尺寸 默认 360.0 / 640.0 / 3.0
setDesignWHD(_designW,_designH,_designD);  
  
// 步骤2
// 在MainPageState build 调用MediaQuery.of(context)
class MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
    // 在 MainPageState build 调用 MediaQuery.of(context)
    MediaQuery.of(context);
    return new Scaffold(
      appBar: new AppBar(),
    );
  }
}  
  
// 步骤3
ScreenUtil.getInstance().screenWidth
ScreenUtil.getInstance().screenHeight
//屏幕适配相关  
ScreenUtil.getInstance().getWidth(size); //返回根据屏幕宽适配后尺寸(单位 dp or pt)
ScreenUtil.getInstance().getHeight(size); //返回根据屏幕高适配后尺寸 (单位 dp or pt)
ScreenUtil.getInstance().getWidthPx(sizePx); //sizePx 单位px
ScreenUtil.getInstance().getHeightPx(sizePx); //sizePx 单位px
ScreenUtil.getInstance().getSp(fontSize); //返回根据屏幕宽适配后字体尺寸
  
double adapterSize = ScreenUtil.getInstance().getAdapterSize(100);

方案二、依赖context

//如果设计稿尺寸默认配置一致,无需该设置。  配置设计稿尺寸 默认 360.0 / 640.0 / 3.0
setDesignWHD(_designW,_designH,_designD);  

ScreenUtil.getScreenW(context); //屏幕 宽
ScreenUtil.getScreenH(context); //屏幕 高
//屏幕适配相关  
ScreenUtil.getScaleW(context, size); //返回根据屏幕宽适配后尺寸(单位 dp or pt)
ScreenUtil.getScaleH(context, size); //返回根据屏幕高适配后尺寸 (单位 dp or pt)
ScreenUtil.getScaleSp(context, size) ;//返回根据屏幕宽适配后字体尺寸
  
double adapterSize = ScreenUtil.getAdapterSizeCtx(context, 100)

Flutter 数据存储 SpUtil

单例"同步" SharedPreferences 工具类。
支持get获取默认参数、支持存储实体对象、支持存储实体对象数组。

    // 等待Sp初始化完成。
    await SpUtil.getInstance();
    
    SpUtil.getString('key', defValue: '');
    SpUtil.getInt('key', defValue: 0);
  
    /// save object example.
    /// 存储实体对象示例。
    City city = new City();
    city.name = "成都市";
    SpUtil.putObject("loc_city", city);
  
    City hisCity = SpUtil.getObj("loc_city", (v) => City.fromJson(v)); 
    print("thll Str: " + (hisCity == null ? "null" : hisCity.toString()));
  
    /// save object list example.
    /// 存储实体对象List示例。
    List<City> list = new List();
    list.add(new City(name: "成都市"));
    list.add(new City(name: "北京市"));
    SpUtil.putObjectList("loc_city_list", list);
  
    List<City> _cityList = SpUtil.getObjList("loc_city_list", (v) => City.fromJson(v));
    print("thll List: " + (_cityList == null ? "null" : _cityList.toString()));

Flutter Demos

  • |--demos
    • |-- city_select_page.dart 城市列表(索引&悬停)示例
    • |-- date_page.dart 日期格式化示例
    • |-- image_size_page.dart 获取图片尺寸示例
    • |-- money_page.dart 金额(元转分/分转元)示例
    • |-- pinyin_page.dart 汉字转拼音示例
    • |-- regex_page.dart 正则工具类示例
    • |-- round_portrait_page.dart 圆形圆角头像示例
    • |-- timeline_page.dart 时间轴示例
    • |-- timer_page.dart 倒计时/定时任务示例
    • |-- widget_page.dart 获取Widget尺寸/屏幕坐标示例

Screenshots

截图无法查看?

掘金地址
简书地址

主界面 启动页 侧滑Back
快速滚动到顶部 分类页面 国际化
主题色 闪屏广告页 引导页

Thanks

① 感谢鸿洋大佬提供的开源api
② 界面参考gitme
Github Trending Api
Streams-Block-Reactive-Programming-in-Flutter

项目问题汇总

Q1:Flutter国际化系统切换iOS不生效问题?
A1:在Xcode项目Localizations下添加支持语言即可,原文

App

Apk:flutter_wanandroid.apk
iOS:请自行clone项目代码运行。

关于作者

GitHub : Sky24n
简书     : Sky24n
掘金     : Sky24n
Email   : 863764940@qq.com

A GitHub client app developed with Flutter, which supports Android iOS Web.
Web :Flutter Web.

About

🔥🔥🔥 基于Google Flutter的WanAndroid客户端,支持Android和iOS。包括BLoC、RxDart 、国际化、主题色、启动页、引导页!

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy