写点什么

一位 Android 程序员入坑 Flutter 后整理出一份超详细的学习笔记

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日

如何启动一个 app

Android 需要在 Manfest 里面指定带有 MAIN action 与 LAUNCHER category 的 Activity 声明,而 Flutter 只需要一行。


void main() => runApp(MyApp());


其中 MyApp 就是一个普通的 Widgets(View).

View vs Widgets

Flutter 没有 View,与之对应的是 Widget,并且分为 StatelessWidgets 与 StatefulWidgets,前者是个静态 View,后者是动态通过 Data 来更新的 View。


  • Stateless


Text(


'I like Flutter!',


);


  • Stateful


class StatefulText extends StatefulWidget {


@override


State<StatefulWidget> createState() => _TextState();


}


class _TextState extends State<StatefulText> {


// Default placeholder text


String textToShow = "I Like Flutter";


void _updateText() {


setState(() {


// update the text


textToShow = "Flutter is Awesome!";


});


}


@override


Widget build(BuildContext context) {


...invoke _updateText


}


}


实际上是因为 StatefulWidgets 通过调用StatesetState方法来触发整个 Widgets 树的重绘,并且在重绘之前会调用传进去的(){ ... }block。

怎么写 Layout, XML 到哪里去了

实际上 Flutter 没有 xml 了, 并且是通过 Widgets 的嵌套来实现一个布局的。


如:


  • Center是一个可以把子 View 放置在中央的容器;

  • Row对应的就是 LinearLayout + Horizontal,Column对应的就是 LinearLayout + Vertical,他们都具备一个属性叫做crossAxisAlignment,有点类似gravity,来控制子 View 相对于父 View 的位置。

  • Expanded支持一个类似 weight 的属性,叫flex

  • Container是一个具有decoration属性的容器,可以用来控制背景色,border, margin 等等。

  • Stack有点像是一个特殊的 RelatetiveLayout 或者 ConstraintLayout,children属性指定了它的子 View,第一个是 Base View,alignment属性指定了后面的子 View 相对于 BaseView 的位置,如`alignm


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


ent: const Alignment(0.6, 0.6)`指定了位于 BaseView 右下角的位置。


  • ListTile是一个特殊的 ListItem,有三个属性,分别是左边的 Icon (leading),文字 (title),以及右边的 Icon (trailing)。

  • 还有诸如ListViewGridViewCard等等比较熟悉的 Widgets。


另外有一个类似于我们 Activity 的 Widgets:


  • 叫做MaterialApp, 可以指定theme,?title, 以及子 View?home, 还有更重要的页面跳转routes.


MaterialApp(


title: 'Welcome to Flutter',


home: ...,


routes: <String, WidgetBuilder> ...,


theme: ThemeData(


primaryColor: Colors.white


),


)


还有一个类似于 Fragment 的:


  • 叫做Scaffold,中文意思是脚手架,它包含一个 appBar (ActionBar)与一个 body,appBar 可以指定 title 与 actions (类似于 action button 的点击事件)。


Scaffold(


appBar: AppBar(


title: Text(widget.title),


actions: <Widget>[...],


),


body: ...,


)

如何从父 View 中 Remove 一个元素

答案是没有... 因为在 Flutter 看来吗,Widgets 的树结构是不可以被更改的,但是如果想更改,则是通过 StatefulWidgets 的方法,通过 setState 来更改 Data,触发 Widgets 重绘,从而替换掉之前的 Widgets。


喜欢画 Canvas 的同学怎么办?


Flutter 同样支持,CustomPaint作为一个 Widgets 就支持传入一个实现CustomPainter抽象类的参数,而CustomPainter的抽象方法也类似于 Android View 的onDraw


void paint(Canvas canvas, Size size)


bool shouldRepaint(CustomPainter oldDelegate)

如何自定义 View

不用继承,而使用类似 Android ViewGroup 的办法,通过组合(composing)与封装的方法来实现,通过小 Widgets 组合成需要的新 Widgets。

页面跳转怎么办,四大组件之一的 Intent 跑哪里去了

貌似在讲类似于 Activity 的MaterialApp的时候剧透了...


就是使用NavigatorRoutes来实现界面跳转,实际上是整个 Widgets 的替换。


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');

如何处理外部的 Intent

实际上还是需要在 Flutter App 的 Android 壳子中注册这个 filter,然后在 FlutterActivity 中拿到存下来。


FlutterView 初始化后再通过 Bridge,官方叫MethodChannel从 Java 里获取,进行下一步逻辑。


可以看个简单的例子:


new MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler(


new MethodCallHandler() {


@Override


public void onMethodCall(MethodCall call, MethodChannel.Result result) {


if (call.method.contentEquals("getSharedText")) {


result.success(sharedText);


sharedText = null;


}


}


});


getSharedText() async {


var sharedData = await platform.invokeMethod("getSharedText");


if (sharedData != null) {


setState(() {


dataShared = sharedData;


});


}


}

常用的 startActivityForResult 怎么办.

这个 Flutter 有完全对应的办法,而且用起来很方便,结合之前说的页面跳转。


Map xxx = await Navigator.of(context).pushNamed('/xxx');


Navigator.of(context).pop({xxx});

异步怎么办, runOnUiThread()哪里去了

Flutter 有点像 JS,是一个单线程模式,所以只是通过模拟来构建简单的异步,关键字就是类似于 kotlin coroutines 一样,通过await+async来处理。


如:


loadData() async {


response = await http.get(xxx);


setState(() {xxx});


}


但是由于它的单线程,所以无法做很长的阻塞操作,像 http 请求的延迟正常情况可能都是毫秒级的,但是数据的处理等,可能就得秒级了。


这也是 RN 在线程方面的做 android 程序的一个痛点,Flutter 采用了比较容易想到的曲线救国的办法,提供了一个叫Isolate的对象,它实际是一个基于 socket 的数据通道,相当于把数据放在一个独立的进程进行处理,然后再通过 socket 发送回程序进程,还记得进程间通信办法之一的管道吗...


具体 API 可以参考文档[1...](


),[2...](


).

Flutter 替代 OkHttp 的网络库

自带了 http 库,直接http.get(url),在线程部分的代码实例里也有涉及。


通过类似 gradle 的文件pubspec.yaml引入。


dependencies:


...


http: ^0.12


^表示不升大版本,并取最新版本,比 gradle 的+要范围更小。

常见的 LCE(Loading Content Error)里面的 Loading 怎么 show

Flutter 有一个 widget 叫做ProgressIndicator,比如我们期望有一个转圈圈的 Loading 界面在数据加载出来之前。


我们就可以通过 StatefulWidgets,根据数据,或者 List Widgets 的个数 (如果是显示一个 List 的话)来判断是否显示 Loading,使用子类CircularProgressIndicator,来替换页面的 Widgets。


当然也是通过 setState(() {...})来触发界面刷新的,可以在 initState()内触发加载数据的异步操作。

不同分辨率的图片资源怎么放

这个有点像 iOS 了, 即有 1x,2x,3x:


images/my_icon.png // Base: 1.0x image


images/2.0x/my_icon.png // 2.0x image


images/3.0x/my_icon.png // 3.0x image


不一样的一点还需要添加到类似 gradle 的文件pubspec.yaml里。


assets:


  • images/my_icon.jpeg

字符串怎么存储

Flutter 没有像 Android 的string.xml的东西,目前来说最好的就就是存成静态字符串。


class Strings {


static String welcomeMessage = "Welcome To Flutter";


}


Text(Strings.welcomeMessage)

Gradle 变成什么了

前面说网络库,图片资源的时候提到过,提供了一个叫pubspec.yaml的文件,具体支持的规则可以查看[这个文档](


)。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
一位Android程序员入坑Flutter后整理出一份超详细的学习笔记