写给前端工程师的 Flutter 详细教程

floatingActionButton:FloatingActionButton()

);

}

}

大杀器:Collection If 和 Collection For

// collection If

Widget build(BuildContext context) {

return Row(

children: [

IconButton(icon: Icon(Icons.menu)),

Expanded(child: title),

if (!isAndroid)

IconButton(icon: Icon(Icons.search)),

],

);

}

// Collect For

var command = [

engineDartPath,

frontendServer,

for (var root in fileSystemRoots) “–filesystem-root=$root”,

for (var entryPoint in entryPoints)

if (fileExists(“lib/ e n t r y P o i n t . j s o n " ) ) " l i b / entryPoint.json")) "lib/ entryPoint.json"))"lib/entryPoint”,

mainPath

];

更多Dart 2.3对此的优化看这里

Flutter 怎么写


到这里终于到正题了,如果熟悉web前端,熟悉React的话,你会对下面要讲的异常的熟悉。

19956127-0be008226088680f.png

Flutter App的一切从 lib/main.dart文件的main函数开始:

import ‘package:flutter/material.dart’;

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

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

title: ‘Welcome to Flutter’,

home: Scaffold(

appBar: AppBar(

title: Text(‘Welcome to Flutter’),

),

body: Center(

child: Text(‘Hello World’),

),

),

);

}

}

Dart 类build方法返回的便是Widget,在Flutter中一切都是Widget,包括但不限于

  • 结构性元素,menu,button等

  • 样式类元素,font,color等

  • 布局类元素,padding,margin等

  • 导航

  • 手势

Widget是Dart中特殊的类,通过实例化(Dart 中new是可选的)相互嵌套,你的这个App就是形如下图的一颗组件树(Dart入口函数的概念,main.dart -> main())。

19956127-edb841cf236c1aa7.png

Widget布局

上说过Flutter布局思路来自CSS,而Flutter中一切皆Widget,因此整体布局也很简单:

  • 容器组件Container

  • decoration装饰属性,设置背景色,背景图,边框,圆角,阴影和渐变等

  • margin

  • padding

  • alignment

  • width

  • height

  • Padding,Center

  • Row,Column,Flex

  • Wrap, Flow流式布局

  • Stack, Z轴布局

  • ……

更多可以看这里

Flutter中Widget可以分为三类,形如React中“展示组件”、“容器组件”,“context”。

StatelessWidget

这个就是Flutter中的“展示组件”,自身不保存状态,外部参数变化就销毁重新创建。Flutter建议尽量使用无状态的组件。

StatefulWidget

状态组件就是类似于React中的“容器组件”了,Flutter中状态组件写法会稍微不一样。

class Counter extends StatefulWidget {

// This class is the configuration for the state. It holds the

// values (in this case nothing) provided by the parent and used by the build

// method of the State. Fields in a Widget subclass are always marked “final”.

@override

_CounterState createState() => _CounterState();

}

class _CounterState extends State {

int _counter = 0;

void _increment() {

setState(() {

// This call to setState tells the Flutter framework that

// something has changed in this State, which causes it to rerun

// the build method below so that the display can reflect the

// updated values. If you change _counter without calling

// setState(), then the build method won’t be called again,

// and so nothing would appear to happen.

_counter++;

});

}

@override

Widget build(BuildContext context) {

// This method is rerun every time setState is called, for instance

// as done by the _increment method above.

// The Flutter framework has been optimized to make rerunning

// build methods fast, so that you can just rebuild anything that

// needs updating rather than having to individually change

// instances of widgets.

return Row(

children: [

RaisedButton(

onPressed: _increment,

child: Text(‘Increment’),

),

Text(‘Count: $_counter’),

],

);

}

}

可以看到Flutter中直接使用了和React中同名的setState方法,不过不会有变量合并的东西,当然也有生命周期

19956127-ba41038574178586.png

可以看到一个有状态的组件需要两个Class,这样写的原因在于,Flutter中Widget都是immmutable的,状态组件的状态保存在State中,组件仍然每次重新创建,Widget在这里只是一种对组件的描述,Flutter会diff转换成Element,然后转换成RenderObject才渲染。

19956127-f8022b0bb6259992.png

Flutter Widget更多的渲染流程可以看 这里

实际上Widget只是作为组件结构一种描述,还可以带来的好处是,你可以更方便的做一些主题性的组件, Flutter官方提供的Material Components widgetsCupertino (iOS-style) widgets质量就相当高,再配合Flutter亚秒级的Hot Reload,开发体验可以说挺不错的。


State Management


setState()可以很方便的管理组件内的数据,但是Flutter中状态同样是从上往下流转的,因此也会遇到和React中同样的问题,如果组件树太深,逐层状态创建就显得很麻烦了,更不要说代码的易读和易维护性了。

InheritedWidget

同样Flutter也有个context一样的东西,那就是InheritedWidget,使用起来也很简单。

class GlobalData extends InheritedWidget {

final int count;

GlobalData({Key key, this.count,Widget child}):super(key:key,child:child);

@override

bool updateShouldNotify(GlobalData oldWidget) {

return oldWidget.count != count;

}

static GlobalData of(BuildContext context) => context.inheritFromWidgetOfExactType(GlobalData);

}

class MyApp extends StatelessWidget {

// This widget is the root of your application.

@override

Widget build(BuildContext context) {

return MaterialApp(

title: ‘Flutter Demo’,

theme: ThemeData(

primarySwatch: Colors.blue,

),

home: MyHomePage(title: ‘Flutter Demo Home Page’),

);

}

}

class MyHomePage extends StatefulWidget {

MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override

_MyHomePageState createState() => _MyHomePageState();

}

class _MyHomePageState extends State {

int _counter = 0;

void _incrementCounter() {

_counter++;

});

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(widget.title),

),

body: GlobalData(

count: _counter,

child: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

Text(

‘You have pushed the button this many times:’,

),

Text(

‘$_counter’,

style: Theme.of(context).textTheme.display1,

),

Body(),

Body2()

],

),

),

),

floatingActionButton: FloatingActionButton(

onPressed: _incrementCounter,

tooltip: ‘Increment’,

child: Icon(Icons.add),

),

);

}

}

class Body extends StatelessWidget {

@override

Widget build(BuildContext context) {

GlobalData globalData = GlobalData.of(context);

return Text(globalData.count.toString());

}

}

class Body2 extends StatelessWidget {

@override

Widget build(BuildContext context) {

// TODO: implement build

GlobalData globalData = GlobalData.of(context);

return Text(globalData.count.toString());

}

具体实现原理可以参考这里,不过Google封装了一个更为上层的库provider,具体使用可以看这里

BlOC

BlOC是Flutter team提出建议的另一种更高级的数据组织方式,也是我最中意的方式。简单来说:

Bloc = InheritedWidget + RxDart(Stream)

Dart语言中内置了Steam,Stream ~= Observable,配合RxDart, 然后加上StreamBuilder会是一种异常强大和自由的模式。

class GlobalData extends InheritedWidget {

final int count;

final Stream timeInterval$ = new Stream.periodic(Duration(seconds: 10)).map((time) => new DateTime.now().toString());

GlobalData({Key key, this.count,Widget child}):super(key:key,child:child);

@override

bool updateShouldNotify(GlobalData oldWidget) {

return oldWidget.count != count;

}

static GlobalData of(BuildContext context) => context.inheritFromWidgetOfExactType(GlobalData);

}

class TimerView extends StatelessWidget {

@override

Widget build(BuildContext context) {

GlobalData globalData = GlobalData.of(context);

return StreamBuilder(

stream: globalData.timeInterval$,

builder: (context, snapshot) {

return Text(snapshot?.data ?? ‘’);

}

);

}

}

当然Bloc的问题在于

  • 学习成本略高,Rx的概念要吃透,不然你会抓狂

  • 自由带来的问题是,可能代码不如Redux类的规整。

顺便,今年Apple也拥抱了响应式,Combine(Rx like) + SwiftUI 也基本等于Bloc了。

所以,Rx还是要赶紧学起来😬

除去Bloc,Flutter中还是可以使用其他的方案,譬如:

展开来说现在的前端开发使用强大的框架页面组装已经不是难点了。开发的难点在于如何组合富交互所需的数据,也就是上面图中的state部分。

更具体来说,是怎么优雅,高效,易维护地处理短暂数据(ephemeral state)setState()和需要共享的App State的问题,这是个工程性的问题,但往往也是日常开发最难的事情了,引用Redux作者Dan的一句:

“The rule of thumb is:Do whatever is less awkward.”

到这里,主要的部分已经讲完了,有这些已经可以开发出一个不错的App了。剩下的就当成一个bonus吧。


测试


Flutter debugger,测试都是出场自带,用起来也不难。

// 测试在/test/目录下面

void main() {

testWidgets(‘Counter increments smoke test’, (WidgetTester tester) async {

// Build our app and trigger a frame.

await tester.pumpWidget(MyApp());

// Verify that our counter starts at 0.

expect(find.text(‘0’), findsOneWidget);

expect(find.text(‘1’), findsNothing);

// Tap the ‘+’ icon and trigger a frame.

await tester.tap(find.byIcon(Icons.add));

await tester.pump();

// Verify that our counter has incremented.

expect(find.text(‘0’), findsNothing);

expect(find.text(‘1’), findsOneWidget);

});

}

包管理,资源管理


类似与JavaScript的npm,Flutter,也就是Dart也有自己的包仓库。不过项目包的依赖使用yaml文件来描述:

name: app

description: A new Flutter project.

version: 1.0.0+1

environment:

sdk: “>=2.1.0 ❤️.0.0”

dependencies:

flutter:

sdk: flutter

cupertino_icons: ^0.1.2

生命周期


移动应用总归需要应用级别的生命周期,flutter中使用生命周期钩子,也非常的简单:

class MyApp extends StatefulWidget {

@override

_MyAppState createState() => new _MyAppState();

}

class _MyAppState extends State with WidgetsBindingObserver {

@override

void initState() {

super.initState();

WidgetsBinding.instance.addObserver(this);

}

@override

void dispose() {

WidgetsBinding.instance.removeObserver(this);

super.dispose();

}

@override

void didChangeAppLifecycleState(AppLifecycleState state) {

switch (state) {

case AppLifecycleState.inactive:

print(‘AppLifecycleState.inactive’);

break;

case AppLifecycleState.paused:

print(‘AppLifecycleState.paused’);

break;

case AppLifecycleState.resumed:

print(‘AppLifecycleState.resumed’);

break;

case AppLifecycleState.suspending:

print(‘AppLifecycleState.suspending’);

break;

}

super.didChangeAppLifecycleState(state);

}

@override

Widget build(BuildContext context) {

return Container();

}

}

使用原生能力


和ReactNative类似,Flutter也是使用类似事件的机制来使用平台相关能力。

19956127-9fab2f7c6d5445b8.png

Flutter Web, Flutter Desktop

这些还在开发当中,鉴于对Dart喜欢,以及对Flutter性能的乐观,这些倒是很值得期待。

19956127-783e3b18ce1553e4.png

还记得平台只是给Flutter提供一个画布么,Flutter Desktop未来更是可以大有可为😄,相关可以看 这里

最后每种方案,每种技术都有优缺点,甚至技术的架构决定了,有些缺陷可能永远都没法改进,所以🤔

原文作者:腾讯技术

原文链接:https://zhuanlan.zhihu.com/p/97653115

来源:知乎

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
[外链图片转存中…(img-xv7VNDmP-1715854482442)]

还记得平台只是给Flutter提供一个画布么,Flutter Desktop未来更是可以大有可为😄,相关可以看 这里

最后每种方案,每种技术都有优缺点,甚至技术的架构决定了,有些缺陷可能永远都没法改进,所以🤔

原文作者:腾讯技术

原文链接:https://zhuanlan.zhihu.com/p/97653115

来源:知乎

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-ulnfExdH-1715854482444)]

[外链图片转存中…(img-dhatleV6-1715854482445)]

[外链图片转存中…(img-Yp5eVt1f-1715854482446)]

[外链图片转存中…(img-0Q74GaLx-1715854482447)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值