去年,我们推出了一个名为 Flat App 的 React Native 入门套件。这个套件包含了一个扁平风格的 UI 设计和适用于 iOS 和 Android 的 Redux 和 NativeBase 组件。Flat App 基本上算是一种界面设计风格,旨在减少对风格元素的使用。众所周知,开发人员更喜欢扁平设计,因为它可以让界面设计变得更简单和高效。作为一项实验,我们使用谷歌的 Flutter 成功地重写了这个应用,结果真的很棒。
在这篇文章中,我将从语言栈、UI、样式和其他方面对 Flutter 和 React Native 进行比较。同时,我还将讨论在重写 Flat App 过程中遇到的一些挑战,以及我们是怎样解决的。
Flutter 是一个由谷歌构建的平台,帮助我们快速构建可以在 Android 和 iOS 平台上运行的应用程序。
Flutter 与众不同的地方是它有一个 C/C++ 层,但系统的大部分都是用 Dart 实现的,开发人员可以轻松地进行读取、替换或移除。这为开发人员提供了灵活的系统控制。
React Native 是一个 JavaScript 库,但 Flutter 却是一个 SDK,它使用的是一门名为 Dart 的编程语言。
虽然 JavaScript 最初是为 Web 开发而生,但到了今天,JavaScript 生态系统已经变得如此庞大,以至于很多地方都能看到它的身影。
React Native 在运行时将动态 JavaScript 代码编译为原生视图,其余代码则通过嵌在应用程序内部的虚拟机来运行。
Dart 是一门由谷歌开发的通用编程语言。它还可用于构建 Web、服务器端、移动端和物联网设备应用程序。
Dart 受到很多编程语言的影响,其中对它影响最大的是 Java。Java 程序员应该很容易看出这两种语言之间的相似之处。
Dart 是一种面向对象的编程语言,支持抽象、封装、继承和多态等特性。
Dart 程序可以在以下两种模式下运行:
Dart 示例:
int fib(int n) => (n > 2) ? (fib(n - 1) + fib(n - 2)) : 1;
void main() {
print('fib(20) = ${fib(20)}');
}
尽管 Dart 拥有强大的社区影响力,但仍然被其他主流语言(如 JavaScript)占了上风,因此很少有开发者了解 Dart。
但这种情况正在发生改变。感谢 Flutter 发布了 Beta 1!在我撰写这篇文章时,Flutter 的 GitHub 代码库(https://github.com/flutter/flutter)已经获得了 18000 个 star!
Flutter 有一个函数反应式框架,主要是受 React 的启发。虽然 Flutter 是用 Dart 编写的,但它也借鉴了 React 的一些最好的特性,帮助开发人员构建出漂亮的跨平台移动应用程序。
在 React Native 中,样式是通过 JavaScript 来定义的。React Native 的所有核心组件都接受名为 style 的 prop。样式名称和值通常与 Web 中的 CSS 类似。唯一的区别是,在 React Native 中,名称采用了驼峰的格式。因此,要定义背景颜色,需要将样式命名为 backgroundColor,而不是 background-color。
如果我们使用 StyleSheet.create 在一个地方定义多个样式,代码就会变得更清晰。随着应用程序变得越来越复杂,这种方式会非常有用。
样式的差异在 Flutter 中比在 React Native 中表现得更为明显。这个从下面给出的例子就可以看出来。
这是一段 React Native 代码,用于定义字体样式和其他文本属性。
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
export default class LotsOfStyles extends Component {
render() {
return (
Lorem Ipsum
);
}
}
const styles = StyleSheet.create({
greybox: {
backgroundColor: #e0e0e0,
width: 320px;
height: 240px;
font: 900 24px Georgia;
}
})
// skip this line if using Create React Native App
AppRegistry.registerComponent('AwesomeProject', () => LotsOfStyles);
如果我们想要在 Flutter 中实现同样的样式,那么可以写成:
var container = new Container( // grey box
child: new Text(
"Lorem ipsum",
style: new TextStyle(
fontSize: 24.0
fontWeight: FontWeight.w900,
fontFamily: "Georgia",
),
),
width: 320.0,
height: 240.0,
color: Colors.grey[300],
);
React Native 应用程序的架构被称为 Flux。Facebook 使用 Flux 构建客户端 Web 应用程序。Flux 使用的是单向数据流。Flux 更像是一种模式,而不是一种正式的框架。任何人都可以轻松使用 Flux,而无需编写大量新代码。
单向数据流是 Flux 的主要概念。
Dispatcher、Store 和 View 是具有不同输入和输出的独立节点。Action 是包含新数据和 type 属性的简单对象。View 可能会产生新的操作,并通过系统传播,以便对用户交互做出响应。
Flutter 有一个名为 Flutter Flux 的 Dart 库。它是一种单向数据流,受到 RefluxJS 和 Facebook Flux 的启发。
Flutter Flux 不受 Flutter 团队的官方支持,只是一个实验性的软件包。
Flutter Flux 几乎与 React/React Native 的实现是一样的,只是使用 Flutter 替换了 React。
Flutter Flux 实现了单向数据流模式,由 Action、Store 和 StoreWatcher 组成。
Action 修改保存在 Store 中的数据。Store 的数据被修改时会触发 View 进行重新渲染。
Flutter Widget 和其他交互源通过调用 Action 对用户的输入做出响应。
使用 React Native 就像使用不包含 CSS 框架的 HTML 一样。
与 Flutter 版本的 Flat App 不同,在使用 React Native 时,我们必须使用第三方库,因为 React Native 没有自己的 UI 组件库。
我们使用了 NativeBase 等组件,它是我们自己创建的开源 UI 组件库。React Native Elements、React Native Material Design 和 Shoutem 是其他可以考虑使用的 UI 库。
Flutter 提供了自己的 UI 组件,以及在 Android 和 iOS 平台上渲染组件的引擎。其中大部分组件符合 Material Design 风格。
我们正在使用 Flutter 的内置组件来开发应用程序的 UI。这些组件称为小部件。我们只需使用正确的小部件,并将正确的 prop 传给小部件,就可以获得我们想要的 UI。
Flutter 中的每个小部件都有它们自己的属性定义,并且可以嵌套在其他小部件中。窗口小部件还可以调用父部件的属性。
Flutter 版本的 Flat App 比 React Native 更好,因为它与原生代码的交互最少。这也是为什么 Flutter 版的 Flat App 的动画会运行得更快。
在 React Native 中,我们也可以桥接原生模块和使用原生 UI 组件。但这在 Flutter 中是不可能的,因为 Flutter 有自己的渲染引擎。
这实际上也是 Flutter 尚未支持谷歌地图的原因。
以下是 Flutter Widget 的几个示例:
Drawer 是一种 Material Design 面板,可从 Scaffold 边缘水平滑动出来,上面显示应用程序的导航链接。下面分别是 Flutter 版 Flat App 的 Drawer 的代码和 React Native 版的代码(SideBar):
Inkwell 定义了一个 Material 矩形区域,可对触摸做出响应。我们使用这个小部件创建涟漪效果,当用户触摸这个区域时就会出现波纹效果。
在 React Native 中,我们不需要创建一个全新的组件来实现这种涟漪效果。React Native 的 TouchableOpacity 已默认具有这样的效果。
顾名思义,GestureDetector 是一个用于检测手势的小部件。GestureDetector 会尝试识别与非空回调相对应的手势。
如果这个小部件有子部件,就会根据子部件调整大小。如果没有子部件,就会根据父部件调整大小。
如下面的代码所示,GestureDetector 小部件将根据 Container 小部件调整大小。
GestureDetector 相当于 React Native 中的 TouchableOpacity。因此,我们不需要为它创建新的部件。
DefaultTabController 是默认的 TabController 小部件,在没有明确指定小部件时会用到。
DefaultTabController 用于与 TabBar 或 TabBarView 共享 TabController。我们使用这个小部件与 TabBar 共享 TabController。
当不方便共享显式创建的 TabController 时就可以使用这个小部件,因为 TabBar 小部件是由无状态父部件或不同的小部件创建的。
在 React Native 版的 Flat App 中,我们使用 Tab Navigator 执行相同的操作。
React Native 背后有一个庞大的社区在支持。
这也是为什么 React Native 拥有比 Flutter 更多的第三方库和插件。
在 React Native 版的 Flat App 中,我们使用了很多不同的第三方库,例如 Calendar、Carousel 和 Modal。
我们将 Flutter 版的 Flat App 与 Firebase 集成在一起来实现登录和注册功能。
在 Flutter 中,我们需要为 iOS 和 Android 平台添加单独的文件。在每个文件中,我们需要添加与平台规则相关的代码。
与 Flutter 应用中使用 Firebase 不是件简单的事。请查看谷歌提供的演示(https://codelabs.developers.google.com/codelabs/flutter-firebase/),了解如何将 Firebase 添加到 Flutter 应用中。
为 Flutter 构建新的插件也很容易,几乎每隔一天就会出现新的 Flutter 插件。