哥哥带你一步步搭建Flutter框架

先来整体了解一下Flutter整体框架结构:

1,Flutter网络框架加持:

详细哥哥已经在之前的两篇文章中做过介绍,有兴趣的请移步:

https://www.jianshu.com/p/90d693395347

https://www.jianshu.com/p/f0806375668d

2,跳转工具加持:

class NavigatorUtil {

static void pushPage(

BuildContext context,

    Widget page, {

String pageName,

    bool needLogin =false,

  }) {

if (context ==null || page ==null)return;

    if (needLogin && !Util.isLogin()) {

pushPage(context, UserLoginPage());

return;

    }

Navigator.push(

context, new CupertinoPageRoute(builder: (ctx) => page));

  }

static void pushWeb(BuildContext context,

      {String title, String titleId, String url, bool isHome:false}) {

if (context ==null || ObjectUtil.isEmpty(url))return;

    if (url.endsWith(".apk")) {

launchInBrowser(url, title: title ?? titleId);

    }else {

Navigator.push(

context,

          new CupertinoPageRoute(

builder: (ctx) =>new WebScaffold(

title: title,

                    titleId: titleId,

                    url: url,

                  )));

    }

}

static void pushTabPage(BuildContext context,

      {String labelId, String title, String titleId, TreeModel treeModel}) {

if (context ==null)return;

    Navigator.push(

context,

        new CupertinoPageRoute(

builder: (ctx) =>new BlocProvider(

child:new TabPage(

labelId: labelId,

                    title: title,

                    titleId: titleId,

                    treeModel: treeModel,

                  ),

                  bloc:new TabBloc(),

                )));

  }

static FuturelaunchInBrowser(String url, {String title})async {

if (await canLaunch(url)) {

await launch(url, forceSafariVC:false, forceWebView:false);

    }else {

throw 'Could not launch $url';

    }

}

}

3,数据类加持

开发思路:把所有接口返回数据都写入一个dart文件中,方便调用。

import 'package:flutter/widgets.dart';

class LanguageModel {

StringtitleId;

  StringlanguageCode;

  StringcountryCode;

  boolisSelected;

  LanguageModel(this.titleId, this.languageCode, this.countryCode,

      {this.isSelected:false});

  LanguageModel.fromJson(Map json)

:titleId = json['titleId'],

        languageCode = json['languageCode'],

        countryCode = json['countryCode'],

        isSelected = json['isSelected'];

  MaptoJson() => {

'titleId':titleId,

        'languageCode':languageCode,

        'countryCode':countryCode,

        'isSelected':isSelected,

      };

  @override

  StringtoString() {

StringBuffer sb =new StringBuffer('{');

    sb.write("\"titleId\":\"$titleId\"");

    sb.write(",\"languageCode\":\"$languageCode\"");

    sb.write(",\"countryCode\":\"$countryCode\"");

    sb.write('}');

    return sb.toString();

  }

}

class SplashModel {

Stringtitle;

  Stringcontent;

  Stringurl;

  StringimgUrl;

  SplashModel({this.title, this.content, this.url, this.imgUrl});

  SplashModel.fromJson(Map json)

:title = json['title'],

        content = json['content'],

        url = json['url'],

        imgUrl = json['imgUrl'];

  MaptoJson() => {

'title':title,

        'content':content,

        'url':url,

        'imgUrl':imgUrl,

      };

  @override

  StringtoString() {

StringBuffer sb =new StringBuffer('{');

    sb.write("\"title\":\"$title\"");

    sb.write(",\"content\":\"$content\"");

    sb.write(",\"url\":\"$url\"");

    sb.write(",\"imgUrl\":\"$imgUrl\"");

    sb.write('}');

    return sb.toString();

  }

}

class VersionModel {

Stringtitle;

  Stringcontent;

  Stringurl;

  Stringversion;

  VersionModel({this.title, this.content, this.url, this.version});

  VersionModel.fromJson(Map json)

:title = json['title'],

        content = json['content'],

        url = json['url'],

        version = json['version'];

  MaptoJson() => {

'title':title,

        'content':content,

        'url':url,

        'version':version,

      };

  @override

  StringtoString() {

StringBuffer sb =new StringBuffer('{');

    sb.write("\"title\":\"$title\"");

    sb.write(",\"content\":\"$content\"");

    sb.write(",\"url\":\"$url\"");

    sb.write(",\"version\":\"$version\"");

    sb.write('}');

    return sb.toString();

  }

}

class ComModel {

Stringversion;

  Stringtitle;

  Stringcontent;

  Stringextra;

  Stringurl;

  StringimgUrl;

  Stringauthor;

  StringupdatedAt;

  inttypeId;

  StringtitleId;

  Widgetpage;

  ComModel(

{this.version,

      this.title,

      this.content,

      this.extra,

      this.url,

      this.imgUrl,

      this.author,

      this.updatedAt,

      this.typeId,

      this.titleId,

      this.page});

  ComModel.fromJson(Map json)

:version = json['version'],

        title = json['title'],

        content = json['content'],

        extra = json['extra'],

        url = json['url'],

        imgUrl = json['imgUrl'],

        author = json['author'],

        updatedAt = json['updatedAt'];

  MaptoJson() => {

'version':version,

        'title':title,

        'content':content,

        'extra':extra,

        'url':url,

        'imgUrl':imgUrl,

        'author':author,

        'updatedAt':updatedAt,

      };

  @override

  StringtoString() {

StringBuffer sb =new StringBuffer('{');

    sb.write("\"version\":\"$version\"");

    sb.write(",\"title\":\"$title\"");

    sb.write(",\"content\":\"$content\"");

    sb.write(",\"url\":\"$url\"");

    sb.write(",\"imgUrl\":\"$imgUrl\"");

    sb.write(",\"author\":\"$author\"");

    sb.write(",\"updatedAt\":\"$updatedAt\"");

    sb.write('}');

    return sb.toString();

  }

}

4,res资源文件加持

不同于Android,有专门的res资源文件管理,那我们就仿造Android来创建一个res包,来实现对各种不同资源的管理。

1,colors

import 'package:flutter/material.dart';

class _Colours {

static const Colorapp_main =Color(0xFF666666);

  static const Colortransparent_80 =Color(0x80000000); //

  static const Colortext_dark =Color(0xFF333333);

  static const Colortext_normal =Color(0xFF666666);

  static const Colortext_gray =Color(0xFF999999);

  static const Colordivider =Color(0xffe5e5e5);

  static const Colorgray_33 =Color(0xFF333333); //51

  static const Colorgray_66 =Color(0xFF666666); //102

  static const Colorgray_99 =Color(0xFF999999); //153

  static const Colorcommon_orange =Color(0XFFFC9153); //252 145 83

  static const Colorgray_ef =Color(0XFFEFEFEF); //153

  static const Colorgray_f0 =Color(0xfff0f0f0); //

  static const Colorgray_f5 =Color(0xfff5f5f5); //

  static const Colorgray_cc =Color(0xffcccccc); //

  static const Colorgray_ce =Color(0xffcecece); //

  static const Colorgreen_1 =Color(0xff009688); //

  static const Colorgreen_62 =Color(0xff626262); //

  static const Colorgreen_e5 =Color(0xffe5e5e5); //

}

Map circleAvatarMap = {

'A': Colors.blueAccent,

  'B': Colors.blue,

  'C': Colors.cyan,

  'D': Colors.deepPurple,

  'E': Colors.deepPurpleAccent,

  'F': Colors.blue,

  'G': Colors.green,

  'H': Colors.lightBlue,

  'I': Colors.indigo,

  'J': Colors.blue,

  'K': Colors.blue,

  'L': Colors.lightGreen,

  'M': Colors.blue,

  'N': Colors.brown,

  'O': Colors.orange,

  'P': Colors.purple,

  'Q': Colors.black,

  'R': Colors.red,

  'S': Colors.blue,

  'T': Colors.teal,

  'U': Colors.purpleAccent,

  'V': Colors.black,

  'W': Colors.brown,

  'X': Colors.blue,

  'Y': Colors.yellow,

  'Z': Colors.grey,

  '#': Colors.blue,

};

Map themeColorMap = {

'gray': _Colours.gray_33,

  'blue': Colors.blue,

  'blueAccent': Colors.blueAccent,

  'cyan': Colors.cyan,

  'deepPurple': Colors.deepPurple,

  'deepPurpleAccent': Colors.deepPurpleAccent,

  'deepOrange': Colors.deepOrange,

  'green': Colors.green,

  'indigo': Colors.indigo,

  'indigoAccent': Colors.indigoAccent,

  'orange': Colors.orange,

  'purple': Colors.purple,

  'pink': Colors.pink,

  'red': Colors.red,

  'teal': Colors.teal,

  'black': Colors.black,

};

2,dimens

class Dimens {

static const doublefont_sp10 =10;

  static const doublefont_sp12 =12;

  static const doublefont_sp14 =14;

  static const doublefont_sp16 =16;

  static const doublefont_sp18 =18;

  static const doublegap_dp5 =5;

  static const doublegap_dp10 =10;

  static const doublegap_dp12 =12;

  static const doublegap_dp15 =15;

  static const doublegap_dp16 =16;

}

3,strings
class Ids {

static const StringtitleHome ='title_home';

  static const StringtitleRepos ='title_repos';

  static const StringtitleEvents ='title_events';

  static const StringtitleSystem ='title_system';

  static const StringtitleBookmarks ='title_bookmarks';

  static const StringtitleCollection ='title_collection';

  static const StringtitleSetting ='title_setting';

  static const StringtitleAbout ='title_about';

  static const StringtitleShare ='title_share';

  static const StringtitleSignOut ='title_signout';

  static const StringtitleLanguage ='title_language';

  static const StringtitleTheme ='title_theme';

  static const StringtitleAuthor ='title_author';

  static const StringtitleOther ='title_other';

  static const StringlanguageAuto ='language_auto';

  static const StringlanguageZH ='language_zh';

  static const StringlanguageTW ='language_tw';

  static const StringlanguageHK ='language_hk';

  static const StringlanguageEN ='language_en';

  static const Stringsave ='save';

  static const Stringmore ='more';

  static const StringrecRepos ='rec_repos';

  static const StringrecWxArticle ='rec_wxarticle';

  static const StringtitleReposTree ='title_repos_tree';

  static const StringtitleWxArticleTree ='title_wxarticle_tree';

  static const StringtitleSystemTree ='title_system_tree';

  static const Stringuser_name ='user_name';

  static const Stringuser_pwd ='user_pwd';

  static const Stringuser_re_pwd ='user_re_pwd';

  static const Stringuser_login ='user_login';

  static const Stringuser_register ='user_register';

  static const Stringuser_forget_pwd ='user_forget_pwd';

  static const Stringuser_new_user_hint ='user_new_user_hint';

  static const Stringconfirm ='confirm';

  static const Stringcancel ='cancel';

  static const Stringjump_count ='jump_count';

}

Map> localizedSimpleValues = {

'en': {

Ids.titleHome:'Home',

    Ids.titleRepos:'Repos',

    Ids.titleEvents:'Events',

    Ids.titleSystem:'System',

    Ids.titleBookmarks:'Bookmarks',

    Ids.titleSetting:'Setting',

    Ids.titleAbout:'About',

    Ids.titleShare:'Share',

    Ids.titleSignOut:'Sign Out',

    Ids.titleLanguage:'Language',

    Ids.languageAuto:'Auto',

  },

  'zh': {

Ids.titleHome:'主页',

    Ids.titleRepos:'项目',

    Ids.titleEvents:'动态',

    Ids.titleSystem:'体系',

    Ids.titleBookmarks:'书签',

    Ids.titleSetting:'设置',

    Ids.titleAbout:'关于',

    Ids.titleShare:'分享',

    Ids.titleSignOut:'注销',

    Ids.titleLanguage:'多语言',

    Ids.languageAuto:'跟随系统',

  },

};

Map>> localizedValues = {

'en': {

'US': {

Ids.titleHome:'Home',

      Ids.titleRepos:'Repos',

      Ids.titleEvents:'Events',

      Ids.titleSystem:'System',

      Ids.titleBookmarks:'Bookmarks',

      Ids.titleCollection:'Collection',

      Ids.titleSetting:'Setting',

      Ids.titleAbout:'About',

      Ids.titleShare:'Share',

      Ids.titleSignOut:'Sign Out',

      Ids.titleLanguage:'Language',

      Ids.languageAuto:'Auto',

      Ids.save:'Save',

      Ids.more:'More',

      Ids.recRepos:'Reco Repos',

      Ids.recWxArticle:'Reco WxArticle',

      Ids.titleReposTree:'Repos Tree',

      Ids.titleWxArticleTree:'Wx Article',

      Ids.titleTheme:'Theme',

      Ids.user_name:'user name',

      Ids.user_pwd:'password',

      Ids.user_re_pwd:'confirm password',

      Ids.user_login:'Login',

      Ids.user_register:'Register',

      Ids.user_forget_pwd:'Forget the password?',

      Ids.user_new_user_hint:'New users? ',

      Ids.confirm:'Confirm',

      Ids.cancel:'Cancel',

      Ids.jump_count:'Jump %\$0\$s',

    }

},

  'zh': {

'CN': {

Ids.titleHome:'主页',

      Ids.titleRepos:'项目',

      Ids.titleEvents:'动态',

      Ids.titleSystem:'体系',

      Ids.titleBookmarks:'书签',

      Ids.titleCollection:'收藏',

      Ids.titleSetting:'设置',

      Ids.titleAbout:'关于',

      Ids.titleShare:'分享',

      Ids.titleSignOut:'注销',

      Ids.titleLanguage:'多语言',

      Ids.languageAuto:'跟随系统',

      Ids.languageZH:'简体中文',

      Ids.languageTW:'繁體中文(台灣)',

      Ids.languageHK:'繁體中文(香港)',

      Ids.languageEN:'English',

      Ids.save:'保存',

      Ids.more:'更多',

      Ids.recRepos:'推荐项目',

      Ids.recWxArticle:'推荐公众号',

      Ids.titleReposTree:'项目分类',

      Ids.titleWxArticleTree:'公众号',

      Ids.titleTheme:'主题',

      Ids.user_name:'用户名',

      Ids.user_pwd:'密码',

      Ids.user_re_pwd:'确认密码',

      Ids.user_login:'登录',

      Ids.user_register:'注册',

      Ids.user_forget_pwd:'忘记密码?',

      Ids.user_new_user_hint:'新用户?',

      Ids.confirm:'确认',

      Ids.cancel:'取消',

      Ids.jump_count:'跳过 %\$0\$s',

    },

    'HK': {

Ids.titleHome:'主頁',

      Ids.titleRepos:'項目',

      Ids.titleEvents:'動態',

      Ids.titleSystem:'體系',

      Ids.titleBookmarks:'書簽',

      Ids.titleCollection:'收藏',

      Ids.titleSetting:'設置',

      Ids.titleAbout:'關於',

      Ids.titleShare:'分享',

      Ids.titleSignOut:'註銷',

      Ids.titleLanguage:'語言',

      Ids.languageAuto:'與系統同步',

      Ids.save:'儲存',

      Ids.more:'更多',

      Ids.recRepos:'推荐项目',

      Ids.recWxArticle:'推荐公众号',

      Ids.titleReposTree:'项目分类',

      Ids.titleWxArticleTree:'公众号',

      Ids.titleTheme:'主題',

      Ids.user_name:'用户名',

      Ids.user_pwd:'密码',

      Ids.user_re_pwd:'确认密码',

      Ids.user_login:'登录',

      Ids.user_register:'注册',

      Ids.user_forget_pwd:'忘记密码?',

      Ids.user_new_user_hint:'新用户?',

      Ids.confirm:'确认',

      Ids.cancel:'取消',

      Ids.jump_count:'跳过 %\$0\$s',

    },

    'TW': {

Ids.titleHome:'主頁',

      Ids.titleRepos:'項目',

      Ids.titleEvents:'動態',

      Ids.titleSystem:'體系',

      Ids.titleBookmarks:'書簽',

      Ids.titleCollection:'收藏',

      Ids.titleSetting:'設置',

      Ids.titleAbout:'關於',

      Ids.titleShare:'分享',

      Ids.titleSignOut:'註銷',

      Ids.titleLanguage:'語言',

      Ids.languageAuto:'與系統同步',

      Ids.save:'儲存',

      Ids.more:'更多',

      Ids.recRepos:'推荐项目',

      Ids.recWxArticle:'推荐公众号',

      Ids.titleReposTree:'项目分类',

      Ids.titleWxArticleTree:'公众号',

      Ids.titleTheme:'主題',

      Ids.user_name:'用户名',

      Ids.user_pwd:'密码',

      Ids.user_re_pwd:'确认密码',

      Ids.user_login:'登录',

      Ids.user_register:'注册',

      Ids.user_forget_pwd:'忘记密码?',

      Ids.user_new_user_hint:'新用户?',

      Ids.confirm:'确认',

      Ids.cancel:'取消',

      Ids.jump_count:'跳过 %\$0\$s',

    }

}

};

4,styles
class TextStyles {

static TextStylelistTitle =TextStyle(

fontSize: Dimens.font_sp16,

    color: Colours.text_dark,

    fontWeight: FontWeight.bold,

  );

  static TextStylelistContent =TextStyle(

fontSize: Dimens.font_sp14,

    color: Colours.text_normal,

  );

  static TextStylelistExtra =TextStyle(

fontSize: Dimens.font_sp12,

    color: Colours.text_gray,

  );

}

class Decorations {

static Decorationbottom =BoxDecoration(

border:Border(bottom:BorderSide(width:0.33, color: Colours.divider)));

}

/// 间隔

class Gaps {

/// 水平间隔

  static WidgethGap5 =new SizedBox(width: Dimens.gap_dp5);

  static WidgethGap10 =new SizedBox(width: Dimens.gap_dp10);

  static WidgethGap15 =new SizedBox(width: Dimens.gap_dp15);

  /// 垂直间隔

  static WidgetvGap5 =new SizedBox(height: Dimens.gap_dp5);

  static WidgetvGap10 =new SizedBox(height: Dimens.gap_dp10);

  static WidgetvGap15 =new SizedBox(height: Dimens.gap_dp15);

}

5,事件总线加持

class StatusEvent {

StringlabelId;

  intstatus;

  intcid;

  StatusEvent(this.labelId, this.status, {this.cid});

}

class ComEvent {

intid;

  Objectdata;

  ComEvent({

this.id,

    this.data,

  });

}

class Event {

static void sendAppComEvent(BuildContext context, ComEvent event) {

// BlocProvider.of(context).sendAppComEvent(event);

  }

static void sendAppEvent(BuildContext context, int id) {

BlocProvider.of(context).sendAppEvent(id);

  }

}

6,database加持

关于Flutter中数据库问题,我在其前面的文章中已经做过详细介绍,想了解的情移步  -  https://www.jianshu.com/p/072ea0b4513c

7,common 公共数据存储加持

1,sp工具类

import 'dart:convert';

import 'package:common_utils/common_utils.dart';

import 'package:flustars/flustars.dart';

import 'package:flutter_wanandroid/common/common.dart';

import 'package:flutter_wanandroid/data/protocol/models.dart';

import 'package:flutter_wanandroid/models/models.dart';

class SpHelper {

/// T 用于区分存储类型

  /// Example.

/// SpHelper.putObject(key, value);

/// SpHelper.putObject(key, value);

/// SpHelper.putObject(key, value);

/// SpHelper.putObject(key, value);

/// SpHelper.putObject(key, value);

///

/// SpHelper.putObject(key, UserModel);

///

  static void putObject(String key, Object value) {

switch (T) {

case int:

SpUtil.putInt(key, value);

break;

      case double:

SpUtil.putDouble(key, value);

break;

      case bool:

SpUtil.putBool(key, value);

break;

      case String:

SpUtil.putString(key, value);

break;

      case List:

SpUtil.putStringList(key, value);

break;

      default:

SpUtil.putObject(key, value);

break;

    }

}

static ObjectgetObject(String key) {

Map map = SpUtil.getObject(key);

    if (map ==null)return null;

    Object obj;

    switch (T) {

case SplashModel:

obj =SplashModel.fromJson(map);

break;

      case LanguageModel:

obj =LanguageModel.fromJson(map);

break;

      case VersionModel:

obj =VersionModel.fromJson(map);

break;

      case UserModel:

obj =UserModel.fromJson(map);

break;

      default:

break;

    }

return obj;

  }

static StringgetThemeColor() {

return SpUtil.getString(Constant.key_theme_color, defValue:'deepPurpleAccent');

  }

}

2,一些公用参数
class Constant {

static const StringkeyLanguage ='key_language';

  static const intstatus_success =0;

  static const Stringserver_address =wan_android;

  static const Stringwan_android ="https://www.wanandroid.com/";

  static const inttype_sys_update =1;

  static const inttype_refresh_all =5;

  static const Stringkey_theme_color ='key_theme_color';

  static const Stringkey_guide ='key_guide';

  static const Stringkey_splash_model ='key_splash_models';

}

class AppConfig {

static const StringappName ='flutter_wanandroid';

  static const Stringversion ='0.2.2';

  static const boolisDebug =true;

}

class LoadStatus {

static const intfail = -1;

  static const intloading =0;

  static const intsuccess =1;

  static const intempty =2;

}

8,状态管理加持

9,工具utils加持

import 'package:common_utils/common_utils.dart';

import 'package:flutter/material.dart';

import 'package:flutter_wanandroid/common/common.dart';

import 'package:flutter_wanandroid/res/index.dart';

import 'package:lpinyin/lpinyin.dart';

class Utils {

static StringgetImgPath(String name, {String format:'png'}) {

return 'assets/images/$name.$format';

  }

static StringgetPinyin(String str) {

return PinyinHelper.getShortPinyin(str).substring(0, 1).toUpperCase();

  }

static ColorgetCircleBg(String str) {

String pinyin =getPinyin(str);

    return getCircleAvatarBg(pinyin);

  }

static ColorgetCircleAvatarBg(String key) {

return circleAvatarMap[key];

  }

static ColorgetChipBgColor(String name) {

String pinyin = PinyinHelper.getFirstWordPinyin(name);

    pinyin = pinyin.substring(0, 1).toUpperCase();

    return nameToColor(pinyin);

  }

static ColornameToColor(String name) {

// assert(name.length > 1);

    final int hash = name.hashCode &0xffff;

    final double hue = (360.0 * hash / (1 <<15)) %360.0;

    return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor();

  }

static StringgetTimeLine(BuildContext context, int timeMillis) {

//    LogUtil.e("countryCode: " +

//        Localizations.localeOf(context).countryCode +

//        "  languageCode: " +

//        Localizations.localeOf(context).languageCode);

    return TimelineUtil.format(timeMillis,

        locale: Localizations.localeOf(context).languageCode,

        dayFormat: DayFormat.Common);

  }

static doublegetTitleFontSize(String title) {

if (ObjectUtil.isEmpty(title) || title.length <10) {

return 18.0;

    }

int count =0;

    List list = title.split("");

    for (int i =0, length = list.length; i < length; i++) {

String ss = list[i];

      if (RegexUtil.isZh(ss)) {

count++;

      }

}

return (count >=10 || title.length >16) ?14.0 :18.0;

  }

/// 0

/// -1

/// 1

  static intgetUpdateStatus(String version) {

String locVersion = AppConfig.version;

    int remote = int.tryParse(version.replaceAll('.', ''));

    int loc = int.tryParse(locVersion.replaceAll('.', ''));

    if (remote <= loc) {

return 0;

    }else {

return (remote - loc >=2) ? -1 :1;

    }

}

static boolisNeedLogin(String pageId) {

if (pageId == Ids.titleCollection) {

return true;

    }

return false;

  }

static intgetLoadStatus(bool hasError, List data) {

if (hasError)return LoadStatus.fail;

    if (data ==null) {

return LoadStatus.loading;

    }else if (data.isEmpty) {

return LoadStatus.empty;

    }else {

return LoadStatus.success;

    }

}

}

10,UI以及自定义控件

你可能感兴趣的:(哥哥带你一步步搭建Flutter框架)