一、icon制作
https://logo.com/dashboard/brand-kit
https://www.appicon.co/#app-icon
必备小工具详见:新电脑初始安装.md
参考文章:iphone有线投屏和无线投屏到macbook|电脑上操控手机
| 应用名 | 下载地址 | 好用程度 | 在电脑上用鼠标操作投屏的ipone |
|---|---|---|---|
| AirServer | 最好用 | 无 | |
| 虫洞 | https://er.run/ | 付费软件(高版本蓝牙有bug) | 有 |
| iMyFone MirrorTo | https://www.imyfone.com/screen-mirror/ | 付费软件($59.99) iMyFone MirrorTo 使用简介 |
| 应用名 | 应用版本 | 存放于 |
|---|---|---|
| AnyGo | AnyGo for Mac 7.0.0激活版 | 百度网盘 |
macOS 打开软件提示“已损坏”怎么解决?无法确认开发者身份解决方案
点击下载:
以访问 UITableView 滑动到最后一个cell自动加载下一页的数据 为例,其需要会员才能解锁文章全部内容。
如果你不是没有任何开发经验,那么你一定知道任何app里都有可能有重用性比较高的控件。所以对于那么重用性比较高的,或者需要你自定义的控件的,我们需要将它们给封装起来,以便下次或者其他app中继续使用。这也正式本节想要说的内容Flutter中如何封装Widget。
下面我从自己实现一个满意的封装,分别介绍你可能用到的三种封装方式
下面我们以登录页的文本框的自定义来谈封装。

1 | /// 蓝色背景按钮(常用于:登录按钮) |
乍看没什么问题,好像很简洁。但当你也用这种方式来实现文本框的时候,其代码如下:
1 | /// 文本框(常用于:登录用户名、密码文本框) |
可见这种函数的方式,没办法处理过多属性的自定义。因为它并不像我们iOS中的UIView,可以对得到的控件在后续再定制。所以,在Flutter中这种函数式的封装不适合,因为它无法满足使用。
附:以下是iOS中的操作:
1 | - (CJTextField *)userNameTextField { |
1 | /// 文本框(常用于:登录用户名、密码文本框) |
使用的时候:
1 | TextField userNameTextField() { |
虽然使用上看似没什么问题,但是整个TextField的继承代码难道你不觉得有更简洁的写法吗?
所以下面将讲解直接继承TextFiled的方法。
1 | /// 文本框(常用于:登录用户名、密码文本框) |
使用时候
1 | // 用户名文本框 |
可见使用继承父类式封装这种方式,不管在封装时候,还是在使用时候,写的代码都是最简洁的。而且后期如果要直接使用系统样式,也只需要改回类名,其他结构和属性都不用动即可。
在前面,我们已经知道使用继承父类式封装这种方式,不管在封装时候,还是在使用时候,写的代码都是最简洁的。而且后期如果要直接使用系统样式,也只需要改回类名,其他结构和属性都不用动即可。
所以,即使是你所定义的类只有一个入参,也一定要遵守使用继承父类式封装的设计规范。
以下以按钮中 textStyle 的传值为例:
1 | import 'package:flutter_baseui_kit/flutter_baseui_kit.dart'; |
附:bad 和 good 两种实现方式的代码分别如下:
bad:
1 | import 'package:flutter/material.dart'; |
good:
1 | import 'package:flutter/material.dart'; |
所以,综上在Flutter中对于一个Widget的封装,我们采用直接继承其父类的方式来处理,且其具体的写法如上。
良好的规范让你的代码不仅看上来更简洁,也让你的代码更加具有可读性,及大大的减少了后期维护的成本。
以下从几个方面谈谈我对Flutter良好的规范的理解。
我们先从页面开始(以登录页的优化为例),然后逐步的从点到面铺开描述。
目标:页面布局、控件定义、事件处理分离。

规范前:未进行任何处理的时候,你的代码是这样的。

规范后**:按规范处理后你代码的效果是这样的,

可见通过处理后Page的整体代码更加简洁了。
写:

不写:

widgets()方法里处理写法如下:

如此通过以上两步后,Widget build中的代码即会变为如下:

如此通过以上几个拆分,我们的Page页面就显得很简洁和很好维护了。
细心的你,可能发现了我们这里有一个系统没有的LoginTextField文本框类。是的,该类是我们自定义封装到Package后来使用的。
对于一个控件怎么封装,详情查看之前的文章《Flutter进阶(2):控件Widget的自定义与封装》
在*build方法里尽量用最少的代码实现整体视图。如下,我们将登录页中的所有Widget通过loginWidgets()*函数封装起来。
在*loginWidgets()方法里实现页面Widgets的布局。而对于Widget的定义为了不让页面布局与控件定义因写在一堆,而造成代码一大坨。我们对每个Widget单独提供定义的函数,如userNameTextField()*即为定义用户文本框的函数。
3、抽离每个Widget的定义
4、封装单个Widget
说完了页面上的Widgets的开发规范,下面就轮到页面上的业务逻辑的开发规范了。
拿登录页需要获取上次登录的账号来说,它的业务是getDefaultLoginAccountAction,下面以混编时候的项目为例
getDefaultLoginAccountAction在Page中的实现一般为:
1 | /// LoginPage.dart 中的业务代码 |
相应的它的调用为:
1 | /// LoginPage.dart 未去解耦时候的登录页 |
可见上述的业务处理getDefaultLoginAccountAction中,掺杂了对页面Page的setState操作,这不适合我们以后只对业务或者只对页面做修改的处理。所以下面我们将它们解耦。

getDefaultLoginAccountAction在ChannelModel中的实现一般为:
1 | /// LoginChannelModel.dart 文件 |
相应的它的调用为:
1 | /// LoginPage.dart 解耦时候的登录页 |
在使用Flutter与原生项目混编的时候,因为涉及到数据传输,所以我们有必要在前期就对传输数据的进行规范统一。
1、进入官网MySQL地址:https://dev.mysql.com/downloads/mysql/ 以下载安装包

2、选择适合您系统的指定MySQL版本,下载安装

3、MySQL安装成功后的截图如下:

遇上-bash: mysql: command not found的情况别着急,这个是因为/usr/local/bin目录下缺失mysql导致,只需要一下方法建立软链接,即可以解决:把mysql安装目录,映射到/usr/local/bin目录下即可,即将本要链接到/usr/bin下的改链接到/usr/local/bin下就好了。命令如下:
sudo ln -s /usr/local/mysql/bin/mysql /usr/local/bin

要想知道怎么去高级的进行混编,那么久需要你首先对官网的混编方式进行分析。所以,下面我们先对官网的混编方式进行分析,然后在进行正式的高级混编。
1 | #Flutter项目路径 |
podhelper.rb在flutter SDK中的路径为:/Applications/flutter/packages/flutter_tools/templates/module/ios/library/Flutter.tmpl


在项目中的路径为:


pod获取Flutter.podspec

获取FlutterPluginRegistrant.podspec

Flutter.podspec和Flutter.framework如果engine文件夹不存在,即不存在我们需要的Flutter.podspec和Flutter.framework,则我们需要从flutter sdk中的如下目录拷贝Flutter.podspec和Flutter.framework,那么Flutter SDK的根目录从哪里找呢?
/Applications/flutter/bin/cache/artifacts/engine/ios/

而这个flutter sdk目录flutter_root_dir的获取,我们只需要从根据flutter_application_path路径下的Generated.xcconfig文件中的FLUTTER_ROOT获取即可。

获取的方法为:
1 | flutter_root_dir = flutter_root(flutter_application_path) |
该flutter_root函数的方法为:

Generated.xcconfig数组的获取方法为:

xcode_backend.sh的目录为/Applications/flutter/packages/flutter_tools/bin/

Python正则re模块介绍
| 含义 | 语法格式 | |
|---|---|---|
| re.compile | 编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用 | re.compile(pattern[, flags]) |
| re.findall | 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。 | findall(string[, pos[, endpos]]) |
关于
| 含义 | 示例 | 参数 | 返回值 | |
|---|---|---|---|---|
| repr() | 函数将对象转化为供解释器读取的形式 | repr(object) | 对象 | 该对象的 string 格式 |
1 | x = 5 |
参考文章:
场景:打包的shell脚本中,需要加入修改文件的py脚本。在shell中要根据py脚本的处理结果进行判断。
1 | # py_modify_env.py |
sh文件
1 | sc_build.sh |
终端执行的命令:
1 | sh sc_build.sh Develop1 |