四、Flutter for iOS Dev

1️⃣Flutter中的UIView相当于什么?

在iOS中,您在UI中创建的大部分内容都是使用视图对象完成的,这些视图对象是UIView类的实例。这些可以充当其他UIView类的容器,它们构成了你的布局。

在Flutter中,与UIView相当的粗糙部分就是一个Widget。小部件并不完全映射到iOS视图,但是当您熟悉Flutter的工作方式时,可以将它们视为“您声明和构建UI的方式”。

但是,这些与UIView有一些不同之处。首先,小部件具有不同的生命周期:它们是不可变的,只有在它们需要改变时才存在。每当小部件或其状态发生变化时,Flutter的框架就会创建一个新的小部件实例树。相比之下,iOS视图在更改时不会被重新创建,而是它是一个可变实体,只能绘制一次,在使用setNeedsDisplay()失效之前不会重绘。

此外,与UIView不同,Flutter的小部件很轻便,部分原因是它们的不变性。因为它们本身并不是视图,也不是直接绘制任何东西,而是描述UI和它的语义,它们在实际视图对象下面“膨胀”。

如果您希望根据进行HTTP调用后收到的数据动态更改UI,请使用StatefulWidget。 在HTTP调用完成之后,告诉Flutter框架小部件的状态已更新,以便它可以更新UI。

2️⃣Text 在flutter中是属于 StatelessWidget

3️⃣我如何动画一个小工具?myapp02

在iOS中,您通过在视图上调用animate(withDuration:animations :)方法来创建动画。在Flutter中,使用动画库将小部件封装在动画小部件中。

4️⃣在Flutter中,使用一个AnimationController,它是一个可以暂停,寻找,停止和反转动画的动画。它需要一个Ticker,用于在vsync发生时发出信号,并在每帧运行时在0和1之间产生线性插值。然后,您创建一个或多个动画并将它们附加到控制器。

例如,您可以使用CurvedAnimation沿插值曲线实现动画。从这个意义上讲,控制器是动画进程的“主”源,CurvedAnimation计算替换控制器默认线性运动的曲线。与小部件一样,Flutter中的动画也用于合成。

在构建小部件树时,将Animation分配给小部件的动画属性(例如FadeTransition的不透明度),并通知控制器启动动画。

5️⃣绘制

在iOS上,您使用CoreGraphics在屏幕上绘制线条和形状。 Flutter拥有基于Canvas类的不同API,还有两个可以帮助您绘制的类:CustomPaint和CustomPainter,后者实现了您的算法以绘制到画布。

Flutter的绘图原理,Flutter框架直接使用Skia引擎来渲染,因此能够控制渲染帧数,从而实现高帧速率。

6️⃣我如何编写异步代码?  myapp03

Dart有一个单线程执行模型,支持Isolates(一种在另一个线程上运行Dart代码的方式),一个事件循环和异步编程。 除非您生成隔离,否则您的Dart代码将在主UI线程中运行,并由事件循环驱动。 Flutter的事件循环相当于iOS主循环 - 即连接到主线程的Looper。

Dart的单线程模型并不意味着您需要将所有操作都作为导致UI冻结的阻止操作运行。 相反,使用Dart语言提供的异步工具(例如async / await)来执行异步工作。

 由于Flutter是单线程的并且运行事件循环(如Node.js),因此您不必担心线程管理或产生后台线程。 如果您正在执行I / O绑定工作(如磁盘访问或网络调用),那么您可以安全地使用async / await并完成。 另一方面,如果您需要进行计算密集型工作以保持CPU繁忙,则您需要将其移至隔离区以避免阻塞事件循环。

7️⃣但是,有时您可能正在处理大量数据,并且UI挂起。 在Flutter中,使用隔离可利用多个CPU内核来执行长时间运行或计算密集型任务。myapp04

隔离区是独立的执行线程,不会与主执行内存堆共享任何内存。 这意味着你不能从主线程访问变量,或者通过调用setState()来更新你的UI。 隔离对他们的名字是真实的,并且不能共享内存(例如以静态字段的形式)。

以下示例以简单的隔离方式显示如何将数据共享回主线程以更新UI。myapp4

loadData() async {

  ReceivePort receivePort = new ReceivePort();

  await Isolate.spawn(dataLoader, receivePort.sendPort);

  // The 'echo' isolate sends its SendPort as the first message

  SendPort sendPort = await receivePort.first;

  List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts");

  setState(() {

    widgets = msg;

  });

}

// The entry point for the isolate

static dataLoader(SendPort sendPort) async {

  // Open the ReceivePort for incoming messages.

  ReceivePort port = new ReceivePort();

  // Notify any other isolates what port this isolate listens to.

  sendPort.send(port.sendPort);

  await for (var msg in port) {

    String data = msg[0];

    SendPort replyTo = msg[1];

    String dataURL = data;

    http.Response response = await http.get(dataURL);

    // Lots of JSON to parse

    replyTo.send(json.decode(response.body));

  }

}

Future sendReceive(SendPort port, msg) {

  ReceivePort response = new ReceivePort();

  port.send([msg, response.sendPort]);

  return response.first;

}

这里,dataLoader()是在它自己的独立执行线程中运行的Isolate。 在隔离区中,您可以执行更多CPU密集型处理(例如解析大型JSON),或执行计算密集型数学(如加密或信号处理)。

8️⃣network requests

如何显示长时间运行任务的进度? myapp05

在Flutter中,使用ProgressIndicator小部件。 通过控制何时通过布尔标志呈现,以编程方式显示进度。 告诉Flutter在长时间运行的任务开始前更新其状态,并在结束后隐藏它。

9️⃣项目结构,本地化,依赖性和资产

1 Json文件加载 :

导入pubspec.yaml头文件

然后使用AssetBundle从代码访问它:

import 'dart:async' show Future;

import 'package:flutter/services.dart' show rootBundle;

Future loadAsset() async {

  return await rootBundle.loadString('my-assets/data.json');

}

2  对于图像,Flutter遵循一种简单的基于密度的格式,如iOS。 图片资产可能是1.0x,2.0x,3.0x或任何其他乘数。 所谓的devicePixelRatio表示单个逻辑像素中物理像素的比例。

资产位于任意文件夹中 - Flutter没有预定义的文件夹结构。 您在pubspec.yaml文件中声明资产(包含位置),Flutter将其拾取。

例如,要将名为my_icon.png的图像添加到您的Flutter项目中,您可能决定将其存储在任意称为图像的文件夹中。 将基础图像(1.0x)放置在图像文件夹中,并将其他变体放在以相应比率乘数命名的子文件夹中

3 本地化

默认情况下,Flutter仅支持US字符串。 如果您需要添加对其他语言的支持,请包含flutter_localizations包。 您可能还需要添加Dart的intl包以使用i10n机器,例如日期/时间格式。

dependencies:

  # ...

  flutter_localizations:

    sdk: flutter

  intl: "^0.15.6"

要使用flutter_localizations包,请在应用部件上指定localizationsDelegates和supportedLocales:

import 'package:flutter_localizations/flutter_localizations.dart';

new MaterialApp(

localizationsDelegates: [

  // Add app-specific localization delegate[s] here

   GlobalMaterialLocalizations.delegate,

   GlobalWidgetsLocalizations.delegate,

],

supportedLocales: [

    const Locale('en', 'US'), // English

    const Locale('he', 'IL'), // Hebrew

    // ... other locales the app supports

  ],

  // ...

)

4 Cocoapods的等价物是什么?我如何添加依赖关系?

在iOS中,您可以通过添加到Podfile来添加依赖项。 Flutter使用Dart的构建系统和Pub包管理器来处理依赖关系。这些工具将原生Android和iOS包装应用程序的构建委托给相应的构建系统。

虽然在您的Flutter项目的iOS文件夹中有一个Podfile,但只有在您添加每个平台集成所需的本地依赖项时才使用它。通常,使用pubspec.yaml在Flutter中声明外部依赖关系。酒吧是寻找Flutter优质包装的好地方。

5 国际化https://flutter.io/tutorials/internationalization

🔟ViewControllers

1  在iOS中,您可以覆盖ViewController的方法以捕获视图本身的生命周期方法,或者在AppDelegate中注册生命周期回调。 在Flutter中,您既没有概念,但是可以通过挂接到WidgetsBinding观察者并监听didChangeAppLifecycleState()更改事件来监听生命周期事件。

🔟1️⃣Layouts

在iOS中,您可能会在UITableView或UICollectionView中显示一个列表。 在Flutter中,你有一个类似的使用ListView的实现。 在iOS中,这些视图具有用于决定行数的委托方法,每个索引路径的单元格以及单元格的大小。

由于Flutter的不可变小部件模式,您将小部件列表传递给您的ListView,并且Flutter负责确保滚动快速而平稳。

1  列表demo myapp06

2  我如何知道哪个列表项被点击?

在iOS中,您可以实现委托方法tableView:didSelectRowAtIndexPath :. 在Flutter中,使用由传入的小部件(the passed-in widgets)提供的触摸处理。

3 动态更新 list列表 myapp07

在iOS中,您更新列表视图的数据,并使用reloadData方法通知表或集合视图。

在Flutter中,如果您要更新setState()内部的小部件列表,您很快就会发现数据不会在视觉上发生变化。 这是因为当调用setState()时,Flutter渲染引擎会查看小部件树以查看是否有任何更改。 当它到达你的ListView时,它执行==检查,并确定两个ListView是相同的。 没有任何改变,所以不需要更新。

为了更新ListView的一个简单方法,在setState()中创建一个新List,并将旧列表中的数据复制到新列表中。 虽然这种方法很简单,但不推荐用于大数据集

推荐的,高效的和有效的方式来建立一个列表使用ListView.Builder。 当您拥有动态列表或包含大量数据的列表时,此方法非常有用。

Scorllview 也可以使用ListView来实现

触摸监听事件

在iOS中,您将GestureRecognizer附加到视图以处理点击事件。 在Flutter中,添加触摸监听器有两种方式:

1如果小部件支持事件检测,则将函数传递给它,并在函数中处理事件。 例如,RaisedButton小部件有一个onPressed参数:

@override

Widget build(BuildContext context) {

  return new RaisedButton(

    onPressed: () {

      print("click");

    },

    child: new Text("Button"),

  );

}

2如果Widget不支持事件检测,则将该Widget封装在GestureDetector中,并将函数传递给onTap参数。

class SampleApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return new Scaffold(

      body: new Center(

        child: new GestureDetector(

          child: new FlutterLogo(

            size: 200.0,

          ),

          onTap: () {

            print("tap");

          },

        ),

      ),

    );

  }

}

访问本地GPS ,相机  ,三方登录  一般都是使用插件的形式

官网原文链接传送 点我

推荐阅读更多精彩内容

  • 译者丨覃云 Flutter 是什么? Flutter 移动应用程序 SDK 是为开发人员提供一种创建快捷、美观的应...
    言射手阅读 6,863评论 1 14
  • 又一年了,在不知不觉中,我们都长大到法定结婚年龄了。之所以意识到这个问题,是因为这个期间正是办喜事的好日子,随着一...
    遇见_更好的自己阅读 65评论 0 1
  • 晚自习是十一点半下课。 谁也没有预料到,像今天这样好的天气,却在这个时候下起了大雨。 他看了看窗台,平时大家都把伞...
    余子岚阅读 98评论 0 1