Flutter学习
常用网址
免费下载 !《AliFlutter 体系化建设和实践》
Flutter 开发文档
Flutter实战
Dart 编程语言概览
pub仓库
main函数使用了(=>)符号, 这是Dart中单行函数或方法的简写。
// =>是return语句的简写
add3(a, b) => a + b;
变量以下划线(_)开头,在Dart语言中使用下划线前缀标识符,会强制其变成私有的。
Widget
Activity、Fragment、view 在Flutter中等价于Widget.
与Android view区别
- Android中View是可变的,当用户交互或数据更新时,可直接调用View的invalidate方法重绘,达到更新UI的目的。
- Flutter的widget是不可改变的因此不能直接更新,而必须使用Widget的状态。Flutter的widget分为有状态和无状态两种。它们的核心特性是相同的,每一帧它们都会重新构建,不同之处在于有状态的Widget有一个State对象,它可以跨帧存储状态数据并恢复它。
Stateless widgets 是不可变的, 这意味着它们的属性不能改变 ,所有的值都是最终的.
Stateful widgets(有状态的部件) 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
- 一个 StatefulWidget类。
- 一个 State 类。 StatefulWidget类本身是不变的,但是 State类在widget生命周期中始终存在.
stateful widget将自身的构建委托给State对象,State对象的build函数负责构建该Widget,当用户交互或数据发生变化时,Widget状态发生改变,调用State的 setState
方法通知它,而后State根据当前的状态信息,重新构建Widget tree
- 在Android中,您可以从父级控件调用addChild或removeChild以动态添加或删除View。 在Flutter中,因为widget是不可变的,所以没有addChild。相反,您可以传入一个函数,该函数返回一个widget给父项,并通过 布尔值控制该widget的创建。
- 在Flutter中,一个自定义widget通常是通过组合其它widget来实现的,而不是继承
- 某些widget属性需要单个widget(child),而其它一些属性,如action,需要一组widgets(children),用方括号[]表示。
布局
Flutter中通过Row和Column来实现线性布局,类似于Android中的LinearLayout控件
row水平,Column竖直
- 对于线性布局,有主轴和纵轴之分,如果布局是沿水平方向,那么主轴就是指水平方向,而纵轴即垂直方向;如果布局沿垂直方向,那么主轴就是指垂直方向,而纵轴就是水平方向。在线性布局中,有两个定义对齐方式的枚举类MainAxisAlignment和CrossAxisAlignment,分别代表主轴对齐和纵轴对齐。
- mainAxisSize:表示Row在主轴(水平)方向占用的空间,默认是MainAxisSize.max,表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度;
- 而MainAxisSize.min表示尽可能少的占用水平空间,当子组件没有占满水平剩余空间,则Row的实际宽度等于所有子组件占用的的水平空间
- textDirection:表示水平方向子组件的布局顺序(是从左往右还是从右往左),默认为系统当前Locale环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)。
- Row和Column都只会在主轴方向占用尽可能大的空间,而纵轴的长度则取决于他们最大子元素的长度
- 如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有最外面的Row或Column会占用尽可能大的空间,里面Row或Column所占用的空间为实际大小
Stack类似FrameLayout很像,都是可以叠加的现实View
flutter中默认组件尺寸单位都是dp
double.infinity,可以使宽度占用尽可能多的空间
常用Widget和属性
- Container:父view,宽高、背景色、圆角、margin
- Padding:EdgeInsets.fromLTRB
- Center:居中
- TextField:输入框(TextEditingController)
- Expanded:填充剩余布局,组件有个参数flex,可以实现比例分配。
height如果不设置 界面显示会有问题,如果要设置,又不能准确的计算出结果,可以使用Expanded - BoxDecoration:圆角,需要放在Container里,实现边框、圆角、阴影、形状、渐变、背景图像
- ShapeDecoration:实现四个边分别指定颜色和宽度、底部线、矩形边色、圆形边色、体育场(竖向椭圆)、 角形(八边角)边色
- UnderlineTabindicator:下划线
- EdgeInsets.only
- Flutter 中官方提供CustomScrollView,让我们能够作何Appbar折叠的效果,并且很容易就能实现下拉刷新和加载更多。
点击
- 在Flutter中,添加触摸监听器有两种方法:如果Widget支持事件监听,则可以将一个函数传递给它并进行处理。例如,RaisedButton有一个onPressed参数
- 如果Widget不支持事件监听,则可以将该Widget包装到GestureDetector中,并将处理函数传递给onTap参数。
- InkWell:点击
MaterialApp
MaterialApp是我们使用 Flutter开发中最常用的符合Material Design设计理念的入口Widget。你可以将它类比成为网页中的html标签,且它自带路由、主题色等功能。
Scaffold
Scaffold通常被用作MaterialApp的子Widget,它会填充可用空间,占据整个窗口或设备屏幕。Scaffold提供了大多数应用程序都应该具备的功能,例如顶部的appBar,底部的bottomNavigationBar,隐藏的侧边栏drawer等。
const Scaffold({
Key key,
this.appBar, // 标题栏
this.body, // 用于显示当前界面主要内容的Widget
this.floatingActionButton, // 一个悬浮在body上的按钮,默认显示在右下角
this.floatingActionButtonLocation, // 用于设置floatingActionButton显示的位置
this.floatingActionButtonAnimator, // floatingActionButton移动到一个新的位置时的动画
this.persistentFooterButtons, // 多状态按钮
this.drawer, // 左侧的抽屉菜单
this.endDrawer, // 右'侧的抽屉菜单
this.bottomNavigationBar,// 底部导航栏。
this.bottomSheet, // 显示在底部的工具栏
this.backgroundColor,// 内容的背景颜色
this.resizeToAvoidBottomPadding = true, // 控制界面内容 body 是否重新布局来避免底部被覆盖,比如当键盘显示的时候,重新布局避免被键盘盖住内容。
this.primary = true,// Scaffold是否显示在页面的顶部
})
AppBar属性
leading 返回键
iconTheme Appbar 上图标的颜色、透明度、和尺寸信息。默认值为 ThemeData.primaryIconTheme
centerTitle 标题是否居中显示,默认值根据不同的操作系统,显示方式不一样。
Flutter AppBar(顶端栏)
Button
RaisedButton :凸起的按钮,其实就是Android中的Material Design风格的Button ,继承自MaterialButton
FlatButton :扁平化的按钮,继承自MaterialButton
OutlineButton :带边框的按钮,继承自MaterialButton
IconButton :图标按钮,继承自StatelessWidget
SizedBox
- 一般是用来限制孩子控件的大小。
- 还有这么一种场景也可以使用SizeBox,就是可以代替padding和container,然后 用来设置两个控件之间的间距,比如在行或列中就可以设置两个控件之间的间距 主要是可以比使用一个padding或者container简单方便 (在Flutter中可能用不同的控件可以实现到相同的目的,尽量使用越简单的widget来实现)
- 控件在整个手机屏幕中间对齐:ConstrainedBox、SizedBox、Center
banner+list三种实现方式
listView
CustomScrollView
ScrollView
debugPrint('classList-' + classList.toString());
Intents
Navigator.push跳页面
- 在Android中,Intents主要有两种使用场景:在Activity之间切换,以及调用外部组件。 Flutter不具有Intents的概念,但如果需要的话,Flutter可以通过Native整合来触发Intents。
- 要在Flutter中切换屏幕,您可以访问路由以绘制新的Widget。 管理多个屏幕有两个核心概念和类:Route 和 Navigator。Route是应用程序的“屏幕”或“页面”的抽象(可以认为是Activity), Navigator是管理Route的Widget。Navigator可以通过push和pop route以实现页面切换。
- 在Flutter中,导航器管理应用程序的路由栈。将路由推入(push)到导航器的栈中,将会显示更新为该路由页面。 从导航器的栈中弹出(pop)路由,将显示返回到前一个路由。
Flutter路由&pop()&Push()全面解析
异步
- flutter没有UI线程,也没有子线程。也就是说,无论是网络请求,数据处理,页面渲染,都是在同一个线程里面,那怎么保障页面渲染不会anr呢?
- Dart是一个单线程的语言,遇到有延迟的运算(比如IO操作、延时执行)时,线程中按顺序执行的运算就会阻塞,用户就会感觉到卡顿,于是通常用异步处理来解决这个问题。当遇到有需要延迟的运算(async)时,将其放入到延迟运算的队列(await)中去,把不需要延迟运算的部分先执行掉,最后再来处理延迟运算的部分。(
延迟队列
) - 在Flutter可以利用多个CPU内核来执行耗时或计算密集型任务。这是通过使用Isolates来完成的。是一个独立的执行线程,它运行时不会与主线程共享任何内存。这意味着你不能从该线程访问变量或通过调用setState来更新你的UI。
聊一聊Flutter Engine线程管理与Dart Isolate机制
异步async、await和Future的使用技巧
我们需要用到 async,await,Future 三兄弟来进行处理。
async ,它是一个延迟计算的标志,标志了把这个任务放到了延迟运算的队列(await)中,通过Future进行返回。
比如说我们的网络请求:
// post请求
static Future<Map> post(String url,
{Map<String, String> params, bool saveCookie = false}) async {
if (params == null) {
params = new Map();
}
String _url = Api.BASE_URL + url;
if (OsApplication.cookie != null) {
params['Cookie'] = OsApplication.cookie;
}
http.Response res = await http.post(_url, body: params);
return _dealWithRes(res, saveCookie: saveCookie);
}
在Dart中,有await标记的运算,其结果值都是一个Future对象,Future不是String类型
Dart规定有async标记的函数,只能由await来调用,比如这样:
String data = await getData();
//get请求,请求返回值为Future<String>类型,即其返回值未来是一个String类型的值
getData() async {
//async关键字声明该函数内部有代码需要延迟执行
return await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"}); //await关键字声明运算为延迟执行,然后return运算结果
}
then
await会阻塞流程,等待紧跟着的的Future执行完毕之后,再执行下一条语句,而如果用了Future.then这个api,那么就不会等待,直接执行下面的语句,等Future执行完了,再调用then这个方法。
dynamic ,var、object
dynamic
所有dart 对象的基础类型,在大多数情况下,不直接使用它 通过它定义的变量会关闭类型检查,这意味着 dynamix x= ‘hal’; x.foo();这段静态类型检查不会报错,但是运行时会crash,因为x 并没有foo() 方法,所以建议大家在编程时不要直接使用dynamic;
var
是一个关键字,意思是"我不关心这里的类型是什么",系统会自动判断类型 runtimeType;
object
是Dart 对象的基类,当你定义: object o =xxx ;时这个时候系统会认为o是个对象,你可以调用o的toString()和hashCode()方法因为Object 提供了这些方法,但是如果你尝试调用o.foo()时,静态类型检查会运行报错。综上不难看出dynamic 与object 的最大的区别是在静态类型检查上。
MethodChannel与原生交互
将 Flutter 集成到现有应用
Flutter 与 Android 的相互通信
File > New > New Module > flutter 新建到自己项目目录下
可以从Native层调用flutter层的dart代码,也可以在flutter层调用Native的代码,而作为通讯桥梁就是MethodChannel,这个类在初始化的时候需要注册一个渠道值。这个值必须是唯一的,并且在使用到的Native层和Flutter层互相对应。
flutter调用Android
注册
static const nativeChannel =
const MethodChannel('com.example.flutter/native');
flutter
Map<String, dynamic> result = {'message': '我从Flutter页面回来了'};
nativeChannel.invokeMethod('goBackWithResult', result);
Android
MethodChannel nativeChannel = new MethodChannel(flutterEngine.getDartExecutor(), CHANNEL_NATIVE);
nativeChannel.setMethodCallHandler((methodCall, result) -> {
switch (methodCall.method) {
//回调
case "goBackWithResult":
// 返回上一页,携带数据
ActivityManager.getInstance().finishActivity(FlutterActivity.class);
Toast.makeText(this, (String) methodCall.argument("message"), Toast.LENGTH_SHORT).show();
break;
case "getSendParams":
result.success(getSendParams());
break;
default:
result.notImplemented();
break;
}
});
异步
Future getSendParams() async {
String params = await _SendFeedBackState.nativeChannel
.invokeMethod('getSendParams', "");
print("getSendParams:" + params);
}
Android调用flutter
Android
Map<String, Object> result = new HashMap<>();
result.put("message", message);
// 创建MethodChannel
MethodChannel flutterChannel = new MethodChannel(flutterEngine.getDartExecutor(), CHANNEL_FLUTTER);
flutterChannel.invokeMethod("onActivityResult", result);
flutter
@override
void initState() {
super.initState();
Future<dynamic> handler(MethodCall call) async {
switch (call.method) {
case 'onActivityResult':
Fluttertoast.showToast(
msg: call.arguments['message'],
toastLength: Toast.LENGTH_SHORT,
);
break;
case 'goBack':
// 返回上一页
if (Navigator.canPop(context)) {
Navigator.of(context).pop();
} else {
nativeChannel.invokeMethod('goBack');
}
break;
}
}
flutterChannel.setMethodCallHandler(handler);
}
其他
使用 ‘尾随逗号’
Flutter中如何使用原生控件或组件
Flutter代码通常涉及构建相当深的树状数据结构,例如在一个build方法中。 为了获得良好的自动格式化,我们建议您采用可选的尾部逗号。添加尾随逗号很简单:始终在函数、方法和构造函数的参数列表末尾添加尾随逗号,以便保留您的编码格式。 这将有助于自动格式化程序为Flutter样式代码插入适当的换行符。
Eventbus
监听特定的
eventeventBus.on<UserLoggedInEvent>().listen((event) {
print(event.user);});
监听所有的
eventeventBus.on().listen((event) {
print(event. runtimeType);});
发送一个
eventeventBus.fire(new UserLoggedInEvent(myUser));
写text先写padding
child: new Padding(
padding: new EdgeInsets.all(10.0),
child: new Text(
'马上登录',
style:
new TextStyle(color: Colors.white, fontSize: 16.0),
),
)),
Flutter学习的更多相关文章
- Flutter 学习资料
Flutter 学习资料: 学习资料 网址 Flutter 中文网 https://flutterchina.club/ <Flutter实战>电子书 https://book.flutt ...
- Flutter学习笔记与整合
1.Dart 面向对象语言,与java类比学习 非常适合移动和Web应用程序 1.dart官网 2.Dark2 中文文档 3.Dart语法学习 4.极客学院Dart学习 5.Flutter与Dart ...
- Flutter学习指南:UI布局和控件
Flutter学习指南:UI布局和控件 - IT程序猿 https://www.itcodemonkey.com/article/11041.html
- Flutter学习笔记(3)--Dart变量与基本数据类型
一.变量 在Dart里面,变量的声明使用var.Object或Dynamic关键字,如下所示: var name = ‘张三’: 在Dart语言里一切皆为对象,所以如果没有将变量初始化,那么它的默认值 ...
- Flutter学习笔记(4)--Dart函数
如需转载,请注明出处:Flutter学习笔记(4)--Dart函数 Dart是一个面向对象的语言,所以函数也是对象,函数属于Function对象,函数可以像参数一样传递给其他函数,这样便于做回调处理: ...
- Flutter学习笔记(5)--Dart运算符
如需转载,请注明出处:Flutter学习笔记(5)--Dart运算符 先给出一个Dart运算符表,接下来在逐个解释和使用.如下: 描述 ...
- Flutter学习笔记(6)--Dart异常处理
如需转载,请注明出处:Flutter学习笔记(6)--Dart异常处理 异常是表示发生了意外的错误,如果没有捕获异常,引发异常的隔离程序将被挂起,并且程序将被终止: Dart代码可以抛出并捕获异常,但 ...
- Flutter学习笔记(8)--Dart面向对象
如需转载,请注明出处:Flutter学习笔记(7)--Dart异常处理 Dart作为高级语言,支持面向对象的很多特性,并且支持基于mixin的继承方式,基于mixin的继承方式是指:一个类可以继承自多 ...
- Flutter学习笔记(9)--组件Widget
如需转载,请注明出处:Flutter学习笔记(9)--组件Widget 在Flutter中,所有的显示都是Widget,Widget是一切的基础,我们可以通过修改数据,再用setState设置数据(调 ...
- Flutter学习笔记(10)--容器组件、图片组件
如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 上一篇Flutter学习笔记(9)--组件Widget我们说到了在Flutter中一个非常重要的理念"一切皆为组件 ...
随机推荐
- [转帖]通过架设Cockpit服务 使用Web浏览器监测管理多个Linux服务器
Cockpit是一个易于使用,轻量级和简单但功能强大的工具,通过单个Web浏览器监视和管理多个远程Linux服务器. 如果你管理着一台 Linux 服务器,那么你可能正在寻找一个可靠的管理工具.为了这 ...
- 【转帖】Linux性能优化(十四)——CPU Cache
一.CPU Cache 1.CPU Cache简介 CPU Cache是位于CPU与内存之间的临时存储器,容量比内存小但交换速度却比内存要快得多.Cache的出现主要是为了解决CPU运算速度与内存读写 ...
- [转帖]引人入胜,实战讲解“Java性能调优六大工具”之linux命令行工具
Java性能调优六大工具之Linux命令行工具 为了能准确获得程序的性能信息,需要使用各种辅助工具.本章将着重介绍用于系统性能分析的各种工具.熟练掌握这些工具,对性能瓶颈定位和系统故障排查都很有帮助. ...
- 2022 倒带 - NutUI
作者:京东零售 于明明 前言 时光飞逝,流年似水,让我们倒带 2022,回首这跌宕起伏一年走过的 "升级之路". NutUI 表现如何? 成绩单等着您打分! 2022 是 NutU ...
- node中的优先从缓存中加载模块与模块的加载规则
执行 node main.js 请问 b模块会被加载几次 //main.js require('./a.js') var fn = require('./b.js') console.log(fn.s ...
- 01显示转换隐私转换 有8个值转为false 显示转换Number的注意点
prompt()函数会弹出一个框,接受用户的输入.但是在实际的开发中.这样的操作是很少. 至少在我做开发的过程中没有使用过.我二没有看见人家在过开发的使用使用. console.log(Number( ...
- 【转载】基于Tablestore Timeline的IM(即时通讯)消息系统架构 - 架构篇
本文原作者:木洛,阿里云高级技术专家,内容有优化和修订,感谢原作者.原文链接:https://developer.aliyun.com/article/698301 IM全称是『Instant Mes ...
- [1] HEVD 学习笔记:HEVD 环境搭建
1. HEVD 概述 + 环境搭建 HEVD作为一个优秀的内核漏洞靶场受到大家的喜欢,这里选择x86的驱动来学习内核漏洞,作为学习笔记记录下来 实验环境 环境 备注 调试主机操作系统 Window ...
- 设计模式学习-使用go实现迭代器模式
迭代器模式 定义 优点 缺点 适用范围 代码实现 参考 迭代器模式 定义 迭代器模式(Iterator Design Pattern),也叫作游标模式(Cursor Design Pattern). ...
- net8来了
11 月 15 日开始的为期三天的 .NET Conf 在线活动的开幕日上,.NET 8作为微软的开源跨平台开发平台正式发布..NET 团队着重强调云.性能.全栈 Blazor.AI 和 .NET M ...