初识Flutter

Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。

Flutter目标是使开发人员能够交付在不同平台上都感觉自然流畅的高性能应用程序。我们兼容滚动行为、排版、图标等方面的差异。

Flutter组件采用现代响应式框架构建,这是从React中获得的灵感,中心思想是用组件(widget)构建UI。 组件描述了在给定其当前配置和状态时他们显示的样子。当组件状态改变,组件会重构它的描述(description),Flutter会对比之前的描述, 以确定底层渲染树从当前状态转换到下一个状态所需要的最小更改。

它也是构建未来的Google Fuchsia应用的主要方式。

Dart语言:

Dart是谷歌开发的计算机编程语言,它被用于web、服务器、移动应用和物联网等领域的开发。它是宽松开源许可证(修改的BSD证书)下的开源软件。
Dart是面向对象的、类定义的、单继承的语言。它的语法类似C语言,可以转译为JavaScript,支持接口(interfaces)、混入(mixins)、抽象类(abstract classes)、具体化泛型(reified generics)、可选类型(optional typing)和sound type system 。

快速开发

毫秒级的热重载,修改后,您的应用界面会立即更新。
Flutter的热重载可帮助您快速地进行测试、构建UI、添加功能并更快地修复错误。在iOS和Android模拟器或真机上可以在亚秒内重载,并且不会丢失状态。

富有表现力和灵活的UI

Flutter内置美丽的Material Design和Cupertino(iOS风格)widget、丰富的motion API、平滑而自然的滑动效果和平台感知,为用户带来全新体验。





现代的,响应式框架

使用Flutter的现代、响应式框架,和一系列基础widget,轻松构建您的用户界面。使用功能强大且灵活的API(针对2D、动画、手势、效果等)解决艰难的UI挑战。

class CounterState extends State<Counter> {
  int counter = 0;

  void increment() {
    // 告诉Flutter state已经改变, Flutter会调用build(),更新显示
    setState(() {
      counter++;
    });
  }

  Widget build(BuildContext context) {
    // 当 setState 被调用时,这个方法都会重新执行.
    // Flutter 对此方法做了优化,使重新执行变的很快
    // 所以你可以重新构建任何需要更新的东西,而无需分别去修改各个widget
    return new Row(
      children: <Widget>[
        new RaisedButton(
          onPressed: increment,
          child: new Text('Increment'),
        ),
        new Text('Count: $counter'),
      ],
    );
  }
}

访问本地功能和SDK

通过平台相关的API、第三方SDK和原生代码让您的应用变得强大易用。 Flutter允许您复用现有的Java、Swift或ObjC代码,访问iOS和Android上的原生系统功能和系统SDK。

统一的应用开发体验

Flutter拥有丰富的工具和库,可以帮助您轻松地同时在iOS和Android系统中实现您的想法和创意。 如果您是一位iOS或Android开发人员,则可以使用Flutter作为视图(View)层, 并可以使用已经用Java / Kotlin / ObjC / Swift完成的部分(Flutter支持混合开发)。

Flutter介绍视频: https://youtu.be/fq4N0hgOWzU

Flutter框架概览

Flutter包括一个现代的响应式框架、一个2D渲染引擎、现成的widget和开发工具。这些组件可以帮助您快速地设计、构建、测试和调试应用程序。

一切皆为widget

Flutter Widget框架概述

Widget是Flutter应用程序用户界面的基本构建块。每个Widget都是用户界面一部分的不可变声明。 与其他将视图、控制器、布局和其他属性分离的框架不同,Flutter具有一致的统一对象模型:widget。

Widget可以被定义为:

  • 一个结构元素(如按钮或菜单)
  • 一个文本样式元素(如字体或颜色方案)
  • 布局的一个方面(如填充)
  • 等等…

Widget根据布局形成一个层次结构。每个widget嵌入其中,并继承其父项的属性。没有单独的“应用程序”对象,相反,根widget扮演着这个角色。

您可以通过告诉框架使用另一个widget替换层次结构中的widget来响应事件,例如用户交互,替换后框架会比较新的和旧的widget,并高效地更新用户界面。

组合 > 集成

Widget本身通常由许多更小的、单一用途widget组成,这些widget结合起来产生强大的效果。例如,Container是一个常用的widget, 由多个widget组成,这些widget负责布局、绘制、定位和调整大小。 您可以用各种方式组合这些以及其他简单的widget,而不是继承容器。

类层次结构很浅且很宽,可以最大限度地增加可能的组合数量。


  • Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.

  • Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

    1.一个 StatefulWidget类。
    2.一个 State类。 StatefulWidget类本身是不变的,但是 State类在widget生命周期中始终存在。

还可以通过与其他widget组合来控制widget的布局。例如,要将widget居中,可以将其封装在Center widget中。有填充、对齐、行、列和网格的widget。 这些布局widget没有自己的可视化表示。相反,他们唯一的目的是控制另一个widget布局的某些方面。要理解widget以某种方式呈现的原因,检查相邻widget通常很有帮助。

分层的框架

Flutter框架是一个分层的结构,每个层都建立在前一层之上。


这个设计的目标是帮助你用更少的代码做更多的事情。例如,Material层是通过组合来自Widget层的基本Widget来构建的, 并且Widgets层本身是通过较低级对象渲染层构建的。

层为构建应用程序提供了许多选项。选择一种自定义的方法来释放框架的全部表现力,或者使用构件层中的构建块,或混合搭配。 您可以实现Flutter提供的所有现成的widget,或者使用Flutter团队用于构建框架的相同工具和技术创建您自己的定制widget。

构建widget

可以通过实现widget的build返回widget树(或层次结构)来定义widget的独特特征 。 这棵树更具体地表示了用户界面的widget层次。例如,工具栏widget的build函数可能返回一个包含一些文本和各种按钮的水平布局。 然后,框架递归地构建widget,直到该所有widget构建完成,然后framework将他们一起添加到树中。

widget的构建函数一般没有副作用。每当它被要求构建时,widget应该返回一个新的widget树,无论widget以前返回的是什么。 Framework会将之前的构建与当前构建进行比较并确定需要对用户界面进行哪些修改。

这种自动比较非常有效,可以实现高性能的交互式应用程序。而构建函数的设计则着重于声明widget是由什么构成的,而不是将用户界面从一个状态更新到另一个状态的(这很复杂性),从而简化了代码。

处理用户交互

如果widget需要根据用户交互或其他因素进行更改,则该widget是有状态的。例如,如果一个widget的计数器在用户点击一个按钮时递增,那么该计数器的值就是该widget的状态。 当该值发生变化时,需要重新构建widget以更新UI。

这些widget将继承StatefulWidget(而不是State)并将它们的可变状态存储在State的子类中。

每当你改变一个State对象时(例如增加计数器),你必须调用setState()来通知框架,框架会再次调用State的构建方法来更新用户界面。

有了独立的状态和widget对象,其他widget可以以同样的方式处理无状态和有状态的widget,而不必担心丢失状态。 父widget可以自由地创造子widget的新实例且不会失去子widget的状态,而不是通过持有子widget来维持其状态。 框架在适当的时候完成查找和重用现有状态对象的所有工作。

Flutter Widget 索引

使用packages

Flutter支持使用由其他开发者贡献给Flutter和Dart生态系统的共享软件包。这使您可以快速构建应用程序,而无需从头开始开发所有应用程序。

现有的软件包支持许多使用场景,例如,网络请求(http),自定义导航/路由处理(fluro), 集成设备API(如url_launcherbattery) 以及使用第三方平台SDK(如 Firebase)。

搜索packages

Packages会被发布到了 Pub 包仓库.

Flutter landing 页面 显示了与Flutter兼容的包。所有已发布的包都支持搜索。

将包依赖项添加到应用程序

要将包’css_colors’添加到应用中,请执行以下操作:

1.添加依赖

  • 打开 pubspec.yaml 文件,然后在dependencies下添加css_colors:

2.下载安装

  • 在 terminal中: 运行 flutter packages get
    或者
  • 在 IntelliJ中: 点击pubspec.yaml文件顶部的’Packages Get’

3.导入

  • 在您的Dart代码中添加相应的import语句.

依赖未发布的packages

即使未在Pub上发布,软件包也可以使用。对于不用于公开发布的专用插件,或者尚未准备好发布的软件包,可以使用其他依赖项选项:

  • 路径依赖: 一个Flutter应用可以依赖一个插件通过文件系统的path:依赖。路径可以是相对的,也可以是绝对的。例如,要依赖位于应用相邻目录中的插件’plugin1’,使用以下语法
dependencies:
  plugin1:
    path: ../plugin1/
  • Git依赖: 你也可以依赖存储在Git仓库中的包。如果软件包位于仓库的根目录中,请使用以下语法:
dependencies:
  plugin1:
    git:
      url: git://github.com/flutter/plugin1.git
  • Git 依赖于文件夹中的包: 默认情况下,Pub假定包位于Git存储库的根目录中。如果不是这种情况,可以使用path参数指定位置,例如:
dependencies:
 package1:
   git:
     url: git://github.com/flutter/packages.git
     path: packages/package1  

使用平台通道编写平台特定的代码

Flutter使用了一个灵活的系统,允许您调用特定平台的API,无论在Android上的Java或Kotlin代码中,还是iOS上的ObjectiveC或Swift代码中均可用。

Flutter平台特定的API支持不依赖于代码生成,而是依赖于灵活的消息传递的方式:

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

  • 宿主监听的平台通道,并接收该消息。然后它会调用特定于该平台的API(使用原生编程语言) - 并将响应发送回客户端,即应用程序的Flutter部分。

消息和响应是异步传递的,以确保用户界面保持响应。

示例:使用Java添加Android平台特定的实现

1.添加平台通道

在android -> java目录中打开MainActivity.java.

接下来,在onCreate里创建MethodChannel并设置一个MethodCallHandler。确保使用与在Flutter客户端使用的通道名称相同。

import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL = "samples.flutter.io/battery";

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
                new MethodCallHandler() {
                    @Override
                    public void onMethodCall(MethodCall call, Result result) {
                        // TODO
                    }
                });
    }
}

然后,将下面的新方法添加到activity类中的,位于onCreate 方法下方:

private int getBatteryLevel() {
  int batteryLevel = -1;
  if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
    BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
    batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
  } else {
    Intent intent = new ContextWrapper(getApplicationContext()).
        registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
        intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
  }

  return batteryLevel;
}

最后,我们完成之前添加的onMethodCall方法。我们需要处理平台方法名为getBatteryLevel,所以我们在call参数中进行检测是否为getBatteryLevel。 这个平台方法的实现只需调用我们在前一步中编写的Android代码,并使用response参数返回成功和错误情况的响应。如果调用未知的方法,我们也会通知返回:

@Override
public void onMethodCall(MethodCall call, Result result) {
    if (call.method.equals("getBatteryLevel")) {
        int batteryLevel = getBatteryLevel();

        if (batteryLevel != -1) {
            result.success(batteryLevel);
        } else {
            result.error("UNAVAILABLE", "Battery level not available.", null);
        }
    } else {
        result.notImplemented();
    }
}         

2.调用平台通道

  static const platform = const MethodChannel('samples.flutter.io/battery');

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

推荐阅读更多精彩内容

  • Content: Flutter框架概况发展概述发展历史框架特性框架结构 快速入门安装Flutter在Mac OS...
    EchoZuo阅读 6,461评论 3 54
  • 本篇为Flutter中文教程系列第一篇,先整体介绍一下Flutter,旨在让您对Flutter有一个基本的认识。如...
    lazydu阅读 12,692评论 2 38
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,811评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,704评论 2 59
  • 1 在单亲家庭长大的小星,既不是那种能够特别能吃苦、特别体谅妈妈的孩子,也不是那种不学无术、游手好闲的姑娘。 当初...
    羊小彩阅读 1,182评论 0 1