Flutter for iOS开发者
1.UIView 和 Widget
1.0 UIView和Widget
在 Flutter 中,你可以粗略地认为 Widget 相当于 UIView 。Widget 和 iOS 中的控件并不完全等价,但当你试图去理解 Flutter 是如何工作的时候,你可以认为它们是“声明和构建 UI 的方法”。
这是因为它们本身并不是什么控件,也不会被直接绘制出什么,而只是 UI 的描述。
1.1 更换UIView
在 iOS 上更新 views,只需要直接改变它们就可以了。
在 Flutter 中,widgets 是不可变的,而且不能被直接更新。你需要去操纵 widget 的 state。这也正是StatefulWidget(有状态的)和StatelessWidget(无状态的) 这一概念的来源。
请记住以下规则:如果一个 widget 在它的 build 方法之外改变(例如,在运行时由于用户的操作而改变),它就是有状态的。如果一个 widget 在一次 build 之后永远不变,那它就是无状态的。但是,即便一个 widget 是有状态的,包含它的父亲 widget 也可以是无状态的,只要父 widget 本身不响应这些变化。
1.2 界面布局
参考文档
使用CupertinoButton 需要导入import 'package:flutter/cupertino.dart';
1.3 添加, 移除子控件
你在父 view 中调用 addSubview() 或在子 view 中调用 removeFromSuperview() 来动态地添加或移除子 views。
在 Flutter 中,由于 widget 不可变,所以没有和 addSubview() 直接等价的东西。作为替代,你可以向 parent 传入一个返回 widget 的函数,并用一个布尔值来控制子 widget 的创建。每次widget发生改变时, 系统都会调用Widget build (BuildContext context){...}
重新布局
1.4 透明度
在 iOS 中,什么东西都会有一个 .opacity 或是 .alpha 的属性。在 Flutter 中,你需要给 widget 包裹一个 Opacity widget 来做到这一点。
1.5 自定义View
在 Flutter 中,你会组合(composing)多个小的 widgets 来构建一个自定义的 widget(而不是扩展它)
1.6 导航栈
//demo演示
// 源码分析
Flutter使用了 Navigator 和 Routes。一个路由是 App 中“屏幕”或“页面”的抽象,而一个 Navigator 是管理多个路由的 widget 。你可以粗略地把一个路由对应到一个 UIViewController。Navigator 的工作原理和 iOS 中 UINavigationController 非常相似,当你想跳转到新页面或者从新页面返回时,它可以 push() 和 pop() 路由。
跳转的两种方法
- 方法一 使用map定义跳转路由
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: "startup name generator1",
// 使用map定义路由
routes: <String, WidgetBuilder>{
'/myview': (BuildContext context) => MyView(),
'/mywidget': (BuildContext context) => MyWidget(),
});
}
}
//
Navigator.of(context).pushNamed('/myview');
- 方法二
Navigator.of(context).push(new MaterialPageRoute(builder: (context){
return new MyWidget();
}));
- POP
Flutter 在pop时可以带一个参数返回
Navigator.pop(context, "第一个按钮");
在push时,需要加上async
和await
() async {
String str = await Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new MyWidget();
}));
print("我是回调回来的 $str");
}();
1.7 UITableView和UICollectionView
在 iOS 中,你可能用 UITableView 或 UICollectionView 来展示一个列表。在 Flutter 中,你可以用 ListView 来达到相似的实现。在 iOS 中,你通过代理方法来确定行数,每一个 index path 的单元格,以及单元格的尺寸。
由于 Flutter 中 widget 的不可变特性,你需要向 ListView 传递一个 widget 列表,Flutter 会确保滚动是快速且流畅的。
class _SampleAppPageState extends State<SampleAppPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: ListView(children: _getListData()),
);
}
_getListData() {
List<Widget> widgets = [];
for (int i = 0; i < 100; i++) {
widgets.add(Padding(padding: EdgeInsets.all(10.0), child: Text("Row $i")));
}
return widgets;
}
}
2 线程和异步
2.1 线程和异步
Dart 是单线程执行模型,但是它支持 Isolate(一种让 Dart 代码运行在其他线程的方式)、事件循环和异步编程.
除非你自己创建一个 Isolate ,否则你的 Dart 代码永远运行在 UI 线程,并由 event loop 驱动。Flutter 的 event loop 和 iOS 中的 main loop 相似——Looper 是附加在主线程上的。
Dart 的单线程模型并不意味着你写的代码一定是阻塞操作,从而卡住 UI。相反,使用 Dart 语言提供的异步工具,例如 async / await ,来实现异步操作.
2.2 网络请求
在 Flutter 中,使用流行的 http package 做网络请求非常简单。它把你可能需要自己做的网络请求操作抽象了出来,让发起请求变得简单。
dependencies:
...
http: ^0.11.3+16
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(dataURL);
setState(() {
widgets = json.decode(response.body);
});
}
2.3 系统自带的loading
getProgressDialog(){
return Center(child: CircularProgressIndicator());
}
3 生命周期
在 iOS 中,你可以重写 ViewController 中的方法来补货它的视图的生命周期,或者在 AppDelegate 中注册生命周期的回调函数。在 Flutter 中没有这两个概念,但你可以通过 hook WidgetsBinding 观察者来监听生命周期事件,并监听 didChangeAppLifecycleState() 的变化事件。
可观察的生命周期事件有:
inactive - 应用处于不活跃的状态,并且不会接受用户的输入。这个事件仅工作在 iOS 平台,在 Android 上没有等价的事件。
paused - 应用暂时对用户不可见,虽然不接受用户输入,但是是在后台运行的。
resumed - 应用可见,也响应用户的输入。
suspending - 应用暂时被挂起,在 iOS 上没有这一事件。