跨端趋势势在必行。
实战项目:flutter实战:搭建登录页与朋友圈列表页
资源
- flutter实战、控件大全
- Flutter Gallery
- 推荐四个Flutter重磅开源APP项目!
a. Flutter精仿抖音
b. Flutter斗鱼APP
c. Flutter豆瓣客户端
d. Flutter开源中国客户端 - https://github.com/Solido/awesome-flutter
- 开发文档、开发文档2
- 在线json转model
Flutter实战
1. 环境搭建
vim ~/.bash_profile
source ~/.bash_profile
vs code下载、flutter sdk、android sudio、android sdk
android studio设置Http Proxy
flutter环境配置详解MAC版、Mac安装配置Flutter注意事项
dart在线编辑
Flutter SDK version is 0.0.0-unknown
vim使用:
gg 跳到第一行的第一个字符
shift+g 跳到文本的最后一行
shift+4 跳到一行的最后一个字符
0 跳转到当前行的第一个字符
2. 开发
自动化生成模板
flutter --version** **2.9.0
flutter packages get
Flutter学习体会
- Dart和JavaScript都是单线程模型
a. Dart 在单线程中是以消息循环机制来运行的,其中包含两个任务队列,一个是“微任务队列” microtask queue,另一个叫做“事件队列” event queue
b. 所有的外部事件任务都在事件队列中,如IO、计时器、点击、以及绘制事件等,而微任务通常来源于Dart内部,并且微任务非常少 - 高性能
a. 开发效率高:基于JIT的快速开发周期;基于AOT的发布包
b. 高性能:Flutter使用自己的渲染引擎来绘制UI;提供流畅、高保真的的UI体验
c. 快速内存分配
d. 类型安全 - 了解widge,StatelessWidge,StatefulWidge及State,及一些原理。
a. StatelessWidge:重写build方法
b. StatefulWidge引入State。 - flutter的三棵树:widge、Element、RenderObject
a. Widget继承自诊断树,canUpdate、createElement
b. Widget只是UI元素的一个配置数据,并且一个Widget可以对应多个Element
- State
a. 当State被改变时,可以手动调用其`setState(),会重新调用其build方法重新构建widget树。 - 了解弹性布局,这个对iOS开发是一个亮点。
- 了解一些基本控件;熟悉调试环境,采坑。
- 在使用Flutter语法时要注意理论。
- 去github上找一些好的项目,阅读熟悉。上手也还是比较快的。看一些好的书籍《如flutter实战》;有好的视频教程也可以留意下。
- Flutter 的嵌套有点烦人。
控件
布局的思想
不用设置宽高,靠内容撑起来,仅设置边距即可。也可以指定宽高。
布局:先绘制大的轮廓,把占位画出来再处理细节。
基础组件
- InkWell:带有涟漪效果,带有点击事件。
- GestureDetector:点击事件
- Material:与InkWell结合使用。裁剪、阴影、墨水效果。
a. 自定义按钮 - Container:可当做UIView使用;
a. 内边距:使用Container包裹与padding结合
b. 按钮实现:decoration:背景;Material与InkWell使用自定义按钮
c. 画线 - BoxDecoration:背景颜色、阴影、圆角、边框等。与Container结合使用
- ClipRRect:裁剪工具,圆角
- BoxShadow:阴影,BoxDecoration属性
a. Offset(0, -2)上边阴影 - Expanded:弹性布局
a. 包裹字符,过长会自动换行,弹性布局;不包裹会导致其他布局异常。
b. 包裹NestedScrollView能正常显示
c. 尽量占满,如标题居中尽量大,其他控件保持原来大小
d. 不好调整的间隙可以expand填充 - Flexible:不需要填充可用的空间
- Padding:内边距,一般与EdgeInsets结合使用
- Row、Cloumn:多个控件时使用,主轴和纵轴,一般结合padding使用。
- Stack:允许子组件堆叠,而
Positioned
用于根据Stack
的四个角来确定子组件的位置。 - MediaQuery:获取系统属性
a. MediaQuery.of(context).padding.top:导航栏高度
b. MediaQuery.of(context).padding.bottom:底部tabbar高度
c. MediaQuery.of(context).size.width:屏幕宽高 - AppBar().preferredSize.height:状态栏高度?
- Center:标题居中使用
- Theme:主题
- TextTheme:标题
- 尺寸限制类容器
a. SizedBox:固定宽高;当做间距使用;也可以被当做占位空容器使用
b. BoxConstraints:限制最大、最小宽高
c. AspectRatio:按比例展示,如固定图片比例- borderRadius
- Divider:分割线
- VoidCallback:类似block
- 动画
a. AnimationController:Duration动画时间、
b. Animation:变化范围
c. CurvedAnimation:曲线动画
d. AnimatedBuilder、FadeTransition、Transform - Icon:加载系统图片
- SmoothStarRating:星组件
- RangeValues:与Range相同
- RangeSliderView:范围控件、SliderView:进度条、CupertinoSwitch:开关控件
- SafeArea:安全区域
- Scaffold
- TextField:文本框
a. decoration:占位
b. style:文本样式
c. onChanged:变化
d. maxLines:行数限制
e. cursorColor光标颜色
f. 取消键盘操作:FocusScope.of(context).requestFocus(FocusNode()); - 加载图片
a. Image.asset、Image.network、AssetImage、NetworkImage
b. 本地图片在yaml配置路径 - Offstage:通过offsatge字段控制child是否显示。场景:启动显示广告后再显示主页
- TabController:滑动tab、DefaultTabController
- 对话框:
AlertDialog
、SimpleDialog
以及Dialog。
a. showDialog:弹框 - 持久化
a. path_provider
b. shared_preferences(SharedPreferences) - Notification:通知冒泡和用户触摸事件冒泡是相似的,但有一点不同:通知冒泡可以中止,但用户触摸事件不行
//定义通知
class MyNotification extends Notification {
MyNotification(this.msg);
final String msg;
}
//监听通知
NotificationListener(
onNotification: (notification) {
setState(() {
_msg+=notification.msg+" ";
});
return true;
},
child: Container();
});
//发送通知
MyNotification("Hi").dispatch(context)
- 网络请求
a. HttpClient
b. Dio
c. WebSocket - 异步操作
a. FutureBuilder
b. StreamBuilder:它可以接收多个异步操作的结果 - showDialog
- CircularProgressIndicator:加载动画
可滚动组件
- SingleChildScrollView:让单个控件可以滚动,用Expanded包裹。不支持基于Sliver的延迟实例化模型
- ListView:与scrollView相同
- GridView:使用Expand包裹
a. scrollDirection
b. padding
c. physics:动画效果
d. gridDelegate - NestedScrollView:支持 _嵌套滑动,_Expanded包裹
a. headerSliverBuilder:SliverList、SliverPersistentHeader
b. body:Container->ListView.builder - CustomScrollView:可以包含多种滚动模型,举个例子,假设有一个页面,顶部需要一个
GridView
,底部需要一个ListView
,而要求整个页面的滑动效果是统一的,即它们看起来是一个整体。如果使用GridView
+ListView
来实现的话,就不能保证一致的滑动效果,因为它们的滚动效果是分离的,所以这时就需要一个"胶水"
a. 自定义slivers:SliverToBoxAdapter
b. SliverAppBar、SliverPadding、SliverList、GridView
c. Sliver共用CustomScrollView
的Scrollable
,所以最终才实现了统一的滑动效果。 - NestedScrollView与CustomScrollView区别
a.CustomScrollView
-是使用Sliver
对象构建任何基于“滚动”布局的最可定制的方法。SingleChildScrollView
和NestedScrollView
都建立在其之上。
b.NestedScrollView
-是为一个非常特殊的用例提供的Wiget-将一个Scrollable对象放置在另一个对象内(在大多数情况下-方向不同)。
常用第三方组件
cached_network_image
- 图片缓存加载和载入效果
- 能很好的处理占位及错误图片
flutter_bloc:介绍
dio:网络请求库
shared_preferences:轻量级的存储类来保存键值对信息
path_provider:文件操作
pull_to_refresh:下拉刷新组件
fluttertoast:toast效果
photo_view:图片查看器
video_player:视频播放器
调试工具
Inspect Widget:view可能溢出
常用效果
1. 自定义导航栏
Widget build(BuildContext context) {
return Container(//外面包裹一层可以设置背景
color: AppTheme.nearlyWhite,
child: SafeArea(//方便控制安全区域
top: false,
child: Scaffold(//系统提供的脚手架
backgroundColor: AppTheme.nearlyWhite,
body:Container()//自定义
))
);
2. 自定义带波纹按钮效果
Container(
width: 140,
height: 40,
decoration: BoxDecoration(//背景
color: Colors.blue,
borderRadius:
const BorderRadius.all(Radius.circular(4.0)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.6),
offset: const Offset(4, 4),
blurRadius: 8.0),
],
),
child: Material(//背景效果
color: Colors.transparent,
child: InkWell(//点击事件
onTap: () {
print("Chat with Us");
},
child: Center(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
'Chat with Us',
style: TextStyle(
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
),
),
),
),
)
问题
wrap与expand在一起就没法计算了
a. InkWell包裹expand
b. flutter create uses directory name rather than package name to check name validity项目文件夹名称不要-
flutter error Invalid
Podfile
file: no implicit conversion of nil into String. ive searched through discussions but I cant seem to fix the issue
移除iOS文件,重新flutter build ios 或者flutter runflutter create -i swift -a kotlin 工程名
a. 创建新的环境Could not build the application for the simulator.Error launching application on iPhone 11.
a. 解决方案Error running pod install
Error launching application on iPhone 11.稍微复杂点功能,mac都带不动。
b. 编译JOT与运行JIT的区别Flutter向后兼容一致性做的真让人头疼
图片资源热更不过来
-
用着热更新就卡主了,切换其他app再切回来。
a.
FutureBuilder放onTap中不执行怎么解决
a. 直接调用方法,FutureBuilder是异步刷新UI用的
b. 需要判断hasData,可能返回多次且data是null。调试错误不是很友好,try...catch。一行一行走下去,看是那个地方报的Crash.目前碰到的是操作了null,判空即可。
model需要判空,在展示UI时也会报错。
CircularProgressIndicator被拉伸
键盘溢出问题:flutter跳转的下一个界面自动弹出了键盘,A RenderFlex overflowed by 77 pixels on the bottom.
a. 溢出部分增加滑动属性;
b.Scaffold
的resizeToAvoidBottomPadding: false
让其遮挡布局;运行android报错
a. FAILURE: Build failed with an exception.
b. What went wrong:A problem occurred configuring root project 'android'.> Could not resolve all artifacts for configuration ':classpath'.-
- thread #16, name = 'io.flutter.worker.4', stop reason = EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=1450 MB, unused=0x0)
frame #0: 0x00000001035e1874 Flutterycc_rgb_convert + 144 Flutter
ycc_rgb_convert:
-> 0x1035e1874 <+144>: strb w20, [x3]
0x1035e1878 <+148>: ldr x20, [x13, x7, lsl #3]
0x1035e187c <+152>: ldr x19, [x12, x19, lsl #3]
0x1035e1880 <+156>: add x19, x19, x20
Target 0: (Runner) stopped.
- thread #16, name = 'io.flutter.worker.4', stop reason = EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=1450 MB, unused=0x0)
异步初始化也挺坑的。
Script '.../packages/flutter_tools/gradle/app_plugin_loader.gradle' line: 18
面试题
https://www.jianshu.com/p/93821c12a825
[Flutter] 一些面试可能会问基础知识
flutter_interview
算是flutter最完整题库了
- Widget 和 element 和 RenderObject 之间的关系?
- Widget是用户界面的一部分,并且是不可变的。
- Element是在树中特定位置Widget的实例。
- RenderObject是渲染树中的一个对象,它的层次结构是渲染库的核心。
- Stream 与 Future是什么关系?
a. Stream 和 Future 是 Dart 异步处理的核心 API。Future 表示稍后获得的一个数据,所有异步的操作的返回值都用 Future 来表示。但是 Future 只能表示一次异步获得的数据。而 Stream 表示多次异步获得的数据。 - Widget 唯一标识Key有那几种?
a. 主要有4种类型的Key:GlobalKey(确保生成的Key在整个应用中唯一,是很昂贵的,允许element在树周围移动或变更父节点而不会丢失状态)、LocalKey、UniqueKey、ObjectKey - State 对象的初始化流程?
- Widget的两种类型是什么?
- PlatFormView
- flutter的四个线程:
UI Runner
、GPU Runner
、IO Runner
,Platform Runner
总结
- 先把一门学精,再学其他的。不要这里学一下哪里学一下。解决问题只看表面,无疑是没有好处。
- 学习一门语言,了解大概,学其语法,熟悉环境。实战。
- iOS的布局方式到flutter需要重新改变下思想,弹性布局还是好用,适配方便。
- github上有很多优秀的库,可以选一到两个,仔细研究。