Flutter 学习

对于好奇的你来说,新生儿Flutter的出世,是不是要👀👀一下,那么各位老铁请坐稳扶好,航班起飞~~
目录
1、 官方简介
2、安装环境
3、Widget介绍
4、动画
5、界面跳转
6、Dart中的异步
7、与原生进行交互
文档参考 max神

1、 官方简介

Flutter
Flutter中文网
Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。

官方自吹:
  • 快速开发: 毫秒级的热重载,修改后,您的应用界面会立即更新。使用丰富的、完全可定制的widget在几分钟内构建原生界面。
  • 富有表现力和灵活的UI: 快速发布聚焦于原生体验的功能。分层的架构允许您完全自定义,从而实现难以置信的快速渲染和富有表现力、灵活的设计
  • 原生性能: Flutter包含了许多核心的widget,如滚动、导航、图标和字体等,这些都可以在iOS和Android上达到原生应用一样的性能。
商业互吹:

Flutter 跨平台方案介绍:https://m.imooc.com/article/30436
与RN的性能对比:https://yq.aliyun.com/articles/637499?spm=a2c4e.11628350.blogcont.1.1f741260znzYpa

参考链接:

深入了解Flutter界面开发(强烈推荐)
沉浸式ListView
为什么移动端跨平台开发不靠谱?
国内少有的Flutter干货分享:Flutter的原理及美团的实践!
头条 Flutter 混合工程实践

2、安装环境

创建程序 :VSCode -> View -> Command palette : Flutter NewProject

运行程序 :Debug -> Start Debuging 

  • Hello World!:
void main() => runApp(Center(child:Text("hello,world!",textDirection: TextDirection.ltr)));

3、Widget介绍

链接:https://flutterchina.club/widgets-intro/
基础Widget:

MaterialApp:该widget在应用程序的根部创建了一些有用的widget,其中包括一个Navigator, 它管理由字符串标识的Widget栈(即页面路由栈)。Navigator可以让您的应用程序在页面之间的平滑的过渡。

Scaffold:实现MaterialDesign布局Widget, 此类提供tabbar,navigationBar和bottomSheets等

Row、 Column: 这些具有弹性空间的布局类Widget可让您在水平(Row)和垂直(Column)方向上创建灵活的布局。其设计是基于web开发中的Flexbox布局模型。
Stack: 取代线性布局 (译者语:和Android中的LinearLayout相似),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于Stack的上下左右四条边的位置。Stacks是基于Web开发中的绝度定位(absolute positioning )布局模型设计的。
Container: Container 可让您创建矩形视觉元素。container 可以装饰为一个BoxDecoration, 如 background、一个边框、或者一个阴影。 Container 也可以具有边距(margins)、填充(padding)和应用于其大小的约束(constraints)。另外, Container可以使用矩阵在三维空间中对其进行变换。
当然还有常用的其他一些Widget就不一一罗列了,exam:Padding、Image、Clip... https://flutterchina.club/widgets/

但是有必要说一下:Cupertino系列Widget是基于iOS设计语言的Widget风格

4、动画

官方详细介绍:https://flutterchina.club/animations/

个人总结:

Flutter 动画不同于iOS动画,一个block执行一个动画

Flutter的动画的核心类为:

AnimationController:控制动画的开始,暂停,与结束,它不关心我在执行什么动画
Animation:这个是一个抽象类,决定动画的数据和变化方式等,可以通过addListener去监听其Value的变化,初始化的时候需要一个AnimationController;
开始一段动画过程:

AnimationController.forward();//开始动画
Animation.value 发生变化,并执行Animation.notifyListener()
监听函数执行 setState()
子Widget 根据Animation的value值进行布局
总结:就是不停的根据Animation的变化进行setState(),Flutter的动画并不关心Widget的布局方式等,只提供动画的数据模型

5、界面跳转

使用了 Navigator 和 Routes。一个路由是 App 中“屏幕”或“页面”的抽象,而一个 Navigator 是管理多个路由的 widget 。你可以粗略地把一个路由对应到一个 UIViewController。Navigator 的工作原理和 iOS 中 UINavigationController 非常相似,当你想跳转到新页面或者从新页面返回时,它可以 push() 和 pop() 路由。

两种方式跳转:

  • 构建路由表
void main() {
  runApp(MaterialApp(
    home: MyAppHome(), // becomes the route named '/'
    routes: <String, WidgetBuilder> {
      '/a': (BuildContext context) => MyPage(title: 'page A'),
      '/b': (BuildContext context) => MyPage(title: 'page B'),
      '/c': (BuildContext context) => MyPage(title: 'page C'),
    },
  ));
}

//跳转
Navigator.of(context).pushNamed('/b');

  • 直接通过widget创建一个路由

Navigator.push(context, new MaterialPageRoute(
                builder: (BuildContext context) => new FTShareHomePage(title: "ShareSDK Flutter Bridge"),
                // fullscreenDialog: true,
              ));
数据回传
//比如push到位置选择界面
Map coordinates = await Navigator.of(context).pushNamed('/location');

//用户选择了位置pop出来
Navigator.of(context).pop({"lat":43.821757,"long":-79.226392});

6、Dart中的异步

1. 先了解代码怎么写

Future<Map> loadData() async {
  String dataURL = "https://jsonplaceholder.typicode.com/posts";
  http.Response response = await http.get(dataURL);
  return json.decode(response.body);
}

//调用
loadData().then((Map data){
    
});

2. 原理其实不重要 (手动滑稽)
  • 官方介绍:

Dart 是单线程执行模型,但是它支持 Isolate(一种让 Dart 代码运行在其他线程的方式)、事件循环和异步编程。除非你自己创建一个 Isolate ,否则你的 Dart 代码永远运行在 UI 线程,并由 event loop 驱动。Flutter 的 event loop 和 iOS 中的 main loop 相似——Looper 是附加在主线程上的。

Dart 的单线程模型并不意味着你写的代码一定是阻塞操作,从而卡住 UI。相反,使用 Dart 语言提供的异步工具,例如 async / await ,来实现异步操作。

  • 进阶介绍:

Flutter,你是怎么把工作放到后台线程的?

7、与原生进行交互

官方介绍链接: https://flutterchina.club/platform-channels/

介绍
  • 应用的Flutter部分通过平台通道(platform channel)将消息发送到其应用程序的所在的宿主(iOS或Android)。

  • 宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言)

代码示例:
  • dart代码怎么写

//创建一个channel
  static const channel = const MethodChannel('com.mob.flutter/sharesdk');

// invokeMethod 方法执行原生方法
  static Future<Map> share(int platform, Map params) async {
    return await channel.invokeMethod("share", [platform, params]);
  }
  
  • 原生层:

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
    
    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    FlutterMethodChannel *channel = [FlutterMethodChannel
                                     methodChannelWithName:@"com.mob.flutter/sharesdk"
                                     binaryMessenger:controller];
    [channel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            if ([call.method isEqualToString:@"share"])
            {
                NSMutableDictionary *params = @{}.mutableCopy;
                NSArray *args = call.arguments;
                [params SSDKSetupShareParamsByText:args.lastObject[@"text"] images:args.lastObject[@"images"] url:args.lastObject[@"url"] title:args.lastObject[@"title"] type:SSDKContentTypeAuto];
                [ShareSDK share:[args.firstObject integerValue]
                     parameters:params
                 onStateChanged:^(SSDKResponseState state,
                                  NSDictionary *userData,
                                  SSDKContentEntity *contentEntity,
                                  NSError *error) {
                     
                     NSMutableDictionary *dic = @{}.mutableCopy;
                     dic[@"state"] = @(state);
                     dic[@"userData"] = userData;
                     dic[@"contentEntity"] = contentEntity.dictionaryValue;
                     dic[@"error"] = error.userInfo;
                     if (result)
                     {
                         result(dic);
                     }
                 }];
            }
        });
        
    }];
    
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

PS:
  • 通道的客户端和宿主通过通道构造函数中传递的通道名称进行连接。单个应用中使用的所有通道名称必须是不同的; 我们建议在通道名称前加一个唯一的“域名前缀”,例如 samples.flutter.io/battery。(flutter 中文网google翻译害死人)

  • setMethodCallHandler 回调不在主线程

Demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345