乐趣区

关于android:爱了阿里大牛最佳总结Flutter进阶学习笔记理论与实战

去年,2019 年无疑是 Flutter 技术热火朝天倒退的一年。

每一个挪动开发者都在为 Flutter 带来的“疾速开发、富裕表现力和灵便的 UI、原生性能”的特色和理念而痴狂,从超级 App 到独立利用,从纯 Flutter 到混合栈,开发者们在不同的场景下乐此不疲的摸索和利用着 Flutter 技术,也在面临着各种各样不同的挑战。

Alibaba 团体内也有越来越多的业务和团队开始尝试 Flutter 技术栈,从闲鱼的一支独秀引领潮流,到现在淘宝特价版、盒马、优酷、飞猪等 BU 业务相继入局,Flutter 的业务利用在团体内也曾经逐步造成趋势。

有幸从一位敌人那里失去 Alibaba 外部出品强推的“Flutter 进阶学习笔记”,秉承好货色的当然要共享的准则,明天就来秀一把,试试这“Flutter 进阶学习笔记”是否也能让你事倍功半!

第一章 为什么 Flutter 是跨平台开发的终极之选

跨平台开发是当下最受欢迎、利用最宽泛的框架之一。能实现跨平台开发的框架也形形色色,让人目迷五色。

最风行的跨平台框架有 Xamarin、PhoneGap、Ionic、Titanium、Monaca、Sencha、jQuery Mobile、React native、Flutter 等等。但这些工具的体现也是高下有别,各有千秋。

在这些风行的框架中,有很多也曾经隐没在了历史的长河中被人慢慢忘记了。但 React native 和 Flutter 这俩框架位置仍旧坚挺,备受欢送。

因为它们俩别离由最弱小的科技巨头 Facebook 和谷歌背书反对。

第二章 在 Windows 上搭建 Flutter 开发环境

  • 应用镜像
  • 零碎要求
  • 获取 Flutter SDK
  • 编辑器设置
  • Android 设置
  • 起步: 配置编辑器
  • 起步: 体验
  • 体验热重载

进阶学习笔记收费分享,如有须要,能够我的【Github】浏览下载

第三章 编写您的第一个 Flutter App

第 1 步: 创立 Flutter app

创立一个简略的、基于模板的 Flutter 应用程序,依照[创立您的第一个 Flutter 利用中的指南的步骤,而后将我的项目命名为 startup_namer(而不是 myapp),接下来你将会批改这个利用来实现最终的 APP。

在这个示例中,你将次要编辑 Dart 代码所在的lib/main.dart 文件,

提醒: 将代码粘贴到利用中时,缩进可能会变形。您能够应用 Flutter 工具主动修复此问题:

Android Studio / IntelliJ IDEA: 右键单击 Dart 代码,而后抉择Reformat Code with dartfmt.

VS Code: 右键单击并抉择Format Document.

Terminal: 运行 flutter format <filename>.

1. 替换 lib/main.dart. 删除 lib / main.dart 中的所有代码,而后替换为上面的代码,它将在屏幕的核心显示“Hello World”.

import'package:flutter/material.dart';
voidmain()=>runApp(newMyApp());
classMyAppextendsStatelessWidget{
@override
Widgetbuild(BuildContextcontext){
returnnewMaterialApp(
title:'Welcome to Flutter',
home:newScaffold(
appBar:newAppBar(title:newText('Welcome to Flutter'),
),
body:newCenter(child:newText('Hello World'),
),
),
);
}}

2. 运行应用程序,你应该看到如下界面.

剖析

本示例创立一个 Material APP。Material 是一种规范的挪动端和 web 端的视觉设计语言。Flutter 提供了一套丰盛的 Material widgets。

main 函数应用了 (=>) 符号, 这是 Dart 中单行函数或办法的简写。

该应用程序继承了 StatelessWidget,这将会使利用自身也成为一个 widget。在 Flutter 中,大多数货色都是 widget,包含对齐 (alignment)、填充(padding) 和布局(layout)

Scaffold 是 Material library 中提供的一个 widget, 它提供了默认的导航栏、题目和蕴含主屏幕 widget 树的 body 属性。widget 树能够很简单。

widget 的次要工作是提供一个 build()办法来形容如何依据其余较低级别的 widget 来显示本人。

本示例中的 body 的 widget 树中蕴含了一个 Center widget, Center widget 又蕴含一个 Text 子 widget。Center widget 能够将其子 widget 树对其到屏幕核心。

第 2 步: 应用内部包(package)

在这一步中,您将开始应用一个名为 english_words 的开源软件包,其中蕴含数千个最罕用的英文单词以及一些实用功能.

您能够 在 pub.dartlang.org 上找到 english_words 软件包以及其余许多开源软件包

1.pubspec 文件治理 Flutter 应用程序的 assets(资源,如图片、package 等)。在 pubspec.yaml 中,将 english_words(3.1.0 或更高版本)增加到依赖项列表,如上面高亮显示的行:

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons:^0.1.0
english_words:^3.1.0

2. 在 Android Studio 的编辑器视图中查看 pubspec 时,单击右上角的 Packages get,这会将依赖包装置到您的我的项目。您能够在控制台中看到以下内容:

flutter packages get
Running "flutter packages get"in startup_namer...
Process finished with exit code 0

3. 在 lib/main.dart 中, 引入 english_words, 如高亮显示的行所示:

import'package:flutter/material.dart';import'package:english_words/english_words.dart';

在您输出时,Android Studio 会为您提供无关库导入的倡议。而后它将出现灰色的导入字符串,让您晓得导入的库尚未应用(到目前为止)

4. 应用 English words 包生成文原本替换字符串“Hello World”.

Tip:“驼峰命名法”(称为“upper camel case”或“Pascal case”), 示意字符串中的每个单词(包含第一个单词)都以大写字母结尾。所以,“uppercamelcase”变成“UpperCamelCase”
进行以下更改, 如高亮局部所示:

import'package:flutter/material.dart';import'package:english_words/english_words.dart';
voidmain()=>runApp(newMyApp());
classMyAppextendsStatelessWidget{
@override
  Widget build(BuildContext context){final wordPair =new WordPair.random();
returnnewMaterialApp(
      title:'Welcome to Flutter',
      home:newScaffold(
        appBar:newAppBar(title:newText('Welcome to Flutter'),
),
        body:newCenter(//child: new Text('Hello World'),
          child:newText(wordPair.asPascalCase),
),
),
);
}}

5. 如果应用程序正在运行,请应用热重载按钮新正在运行的应用程序。每次单击热重载或保留我的项目时,都会在正在运行的应用程序中随机抉择不同的单词对。这是因为单词对是在 build 办法外部生成的。每次 MaterialApp 须要渲染时或者在 Flutter Inspector 中切换平台时 build 都会运行.

遇到问题?

如果您的利用程序运行不失常,请查找是否有拼写错误。如果须要,应用上面链接中的代码来比照更正。

· pubspec.yaml (The pubspec.yaml file won’t change again.)

· lib/main.dart

第 3 步: 增加一个有状态的部件(Stateful widget)

Stateless widgets 是不可变的, 这意味着它们的属性不能扭转 – 所有的值都是最终的.

Stateful widgets 持有的状态可能在 widget 生命周期中发生变化. 实现一个 stateful widget 至多须要两个类:

1. 一个 StatefulWidget 类。

2. 一个 State 类。StatefulWidget 类自身是不变的,然而 State 类在 widget 生命周期中始终存在.
在这一步中,您将增加一个有状态的 widget-RandomWords,它创立其 State 类 RandomWordsState。State 类将最终为 widget 保护倡议的和喜爱的单词对。

1. 增加有状态的 RandomWords widget 到 main.dart。它也能够在 MyApp 之外的文件的任何地位应用,然而本示例将它放到了文件的底部。RandomWords widget 除了创立 State 类之外简直没有其余任何货色

classRandomWordsextendsStatefulWidget{
@override
createState()=>newRandomWordsState();}

2. 增加 RandomWordsState 类. 该应用程序的大部分代码都在该类中,该类持有 RandomWords widget 的状态。这个类将保留随着用户滚动而有限增长的生成的单词对,以及喜爱的单词对,用户通过反复点击心形 ❤️ 图标来将它们从列表中增加或删除。

你会一步一步地建设这个类。首先,通过增加高亮显示的代码创立一个最小类

class RandomWordsState extends State<RandomWords>{}

3. 在增加状态类后,IDE 会提醒该类短少 build 办法。接下来,您将增加一个根本的 build 办法,该办法通过将生成单词对的代码从 MyApp 挪动到 RandomWordsState 来生成单词对。

将 build 办法增加到 RandomWordState 中,如上面高亮代码所示

classRandomWordsStateextendsState<RandomWords>{
@override
Widget build(BuildContext context){final wordPair =new WordPair.random();
returnnew Text(wordPair.asPascalCase);
}}

4. 通过上面高亮显示的代码,将生成单词对代的码从 MyApp 挪动到 RandomWordsState 中

classMyAppextendsStatelessWidget{
@override
  Widget build(BuildContext context){final wordPair =new WordPair.random();// 删除此行

returnnewMaterialApp(
      title:'Welcome to Flutter',
      home:newScaffold(
        appBar:newAppBar(title:newText('Welcome to Flutter'),
),
        body:newCenter(//child: new Text(wordPair.asPascalCase),
          child:newRandomWords(),),
),
);
}}

重新启动应用程序。如果您尝试热重载,则可能会看到一条正告:

Reloading...
Not all changed program elements ran during view reassembly; consider
restarting.

这可能是误报,但思考到重新启动能够确保您的更改在利用界面中失效。
应用程序应该像之前一样运行,每次热重载或保留应用程序时都会显示一个单词对。


遇到问题?

如果您的利用程序运行不失常,能够应用上面链接中的代码来比照更正。

· lib/main.dart

第 4 步: 创立一个有限滚动 ListView

在这一步中,您将扩大(继承)RandomWordsState 类,以生成并显示单词对列表。当用户滚动时,ListView 中显示的列表将有限增长。ListView 的 builder 工厂构造函数容许您按需建设一个懒加载的列表视图。

1. 向 RandomWordsState 类中增加一个_suggestions 列表以保留倡议的单词对。该变量以下划线(_)结尾,在 Dart 语言中应用下划线前缀标识符,会强制其变成公有的。

另外,增加一个 biggerFont 变量来增大字体大小

classRandomWordsStateextendsState<RandomWords>{final _suggestions =<WordPair>[];

final _biggerFont =constTextStyle(fontSize:18.0);
...}

2. 向 RandomWordsState 类增加一个 _buildSuggestions() 函数. 此办法构建显示倡议单词对的 ListView。
ListView 类提供了一个 builder 属性,itemBuilder 值是一个匿名回调函数,承受两个参数 - BuildContext 和行迭代器 i。迭代器从 0 开始,每调用一次该函数,i 就会自增 1,对于每个倡议的单词对都会执行一次。该模型容许倡议的单词对列表在用户滚动时有限增长。
增加如下高亮的行:

classRandomWordsStateextendsState<RandomWords>{
...
Widget _buildSuggestions(){
returnnew ListView.builder(padding:const EdgeInsets.all(16.0),
// 对于每个倡议的单词对都会调用一次 itemBuilder,而后将单词对增加到 ListTile 行中
// 在偶数行,该函数会为单词对增加一个 ListTile row.
// 在奇数行,该函数会增加一个分割线 widget,来分隔相邻的词对。// 留神,在小屏幕上,分割线看起来可能比拟吃力。itemBuilder:(context, i){
// 在每一列之前,增加一个 1 像素高的分隔线 widget
if(i.isOdd)returnnew Divider();

// 语法 "i ~/ 2" 示意 i 除以 2,但返回值是整形(向下取整),比方 i 为:1, 2, 3, 4, 5
// 时,后果为 0, 1, 1, 2, 2,这能够计算出 ListView 中减去分隔线后的理论单词对数量
final index = i ~/2;
// 如果是倡议列表中最初一个单词对
if(index >= _suggestions.length){
// ... 接着再生成 10 个单词对,而后增加到倡议列表
_suggestions.addAll(generateWordPairs().take(10));
}
return_buildRow(_suggestions[index]);
}
);
}}

3. 对于每一个单词对,_buildSuggestions 函数都会调用一次_buildRow。这个函数在 ListTile 中显示每个新词对,这使您在下一步中能够生成更丑陋的显示行
在 RandomWordsState 中增加一个_buildRow 函数 :

classRandomWordsStateextendsState<RandomWords>{
...

Widget _buildRow(WordPair pair){
returnnew ListTile(
title:new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
}}
4. 更新 RandomWordsState 的 build 办法以应用_buildSuggestions(),而不是间接调用单词生成库。更改后如上面高亮局部:classRandomWordsStateextendsState<RandomWords>{
...
@override
  Widget build(BuildContext context){final wordPair =new WordPair.random();// 删除这两行
returnnew Text(wordPair.asPascalCase);
returnnew Scaffold (
appBar:new AppBar(title:new Text('Startup Name Generator'),
),
body:_buildSuggestions(),);
}
...}\

5. 更新 MyApp 的 build 办法。从 MyApp 中删除 Scaffold 和 AppBar 实例。这些将由 RandomWordsState 治理,这使得用户在下一步中从一个屏幕导航到另一个屏幕时,能够更轻松地更改导航栏中的的路由名称。
用上面高亮局部替换最后的 build 办法:

classMyAppextendsStatelessWidget{
@override
Widget build(BuildContext context){
returnnew MaterialApp(
title:'Startup Name Generator',
home:new RandomWords(),);
}}

重新启动应用程序。你应该看到一个单词对列表。尽可能地向下滚动,您将持续看到新的单词对。

遇到问题?

如果你的利用没有失常运行,你能够应用一下链接中的代码比照更正。

· lib/main.dart

第 5 步: 增加交互

在这一步中,您将为每一行增加一个可点击的心形 ❤️ 图标。当用户点击列表中的条目,切换其“珍藏”状态时,将该词对增加到或移除出“收藏夹”。

1. 增加一个 _saved Set(汇合) 到 RandomWordsState。这个汇合存储用户喜爱(珍藏)的单词对。在这里,Set 比 List 更适合,因为 Set 中不容许反复的值。

classRandomWordsStateextendsState<RandomWords>{final _suggestions =<WordPair>[];

final _saved =new Set<WordPair>();

final _biggerFont =constTextStyle(fontSize:18.0);
...}

2. 在 _buildRow 办法中增加 alreadySaved 来查看确保单词对还没有增加到收藏夹中。

Widget _buildRow(WordPair pair){final alreadySaved = _saved.contains(pair);
...}

3. 同时在 _buildRow()中,增加一个心形 ❤️ 图标到 ListTiles 以启用珍藏性能。接下来,你就能够给心形 ❤️ 图标增加交互能力了。
增加上面高亮的行:

Widget _buildRow(WordPair pair){final alreadySaved = _saved.contains(pair);
returnnewListTile(
    title:newText(
      pair.asPascalCase,
      style: _biggerFont,
),
trailing:new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red :null,
),
);}

4. 重新启动利用。你当初能够在每一行看到心形❤️图标️,但它们还没有交互。
在 _buildRow 中让心形❤️图标变得能够点击。如果单词条目曾经增加到收藏夹中,再次点击它将其从收藏夹中删除。当心形❤️图标被点击时,函数调用 setState()告诉框架状态曾经扭转。
增加如下高亮的行:

Widget _buildRow(WordPair pair){final alreadySaved = _saved.contains(pair);
returnnewListTile(
    title:newText(
      pair.asPascalCase,
      style: _biggerFont,
),
    trailing:newIcon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red :null,
),
onTap:(){setState((){if(alreadySaved){_saved.remove(pair);
}else{_saved.add(pair);
}
});
},
);}

提醒: 在 Flutter 的响应式格调的框架中,调用 setState() 会为 State 对象触发 build()办法,从而导致对 UI 的更新
热重载你的利用。你就能够点击任何一行珍藏或移除。请留神,点击一行时会生成从心形 ❤️ 图标收回的水波动画.

遇到了问题?

如果您的利用没有失常运行,请查看上面链接处的代码,比照更正。

· lib/main.dart

第 6 步: 导航到新页面

在这一步中,您将增加一个显示收藏夹内容的新页面(在 Flutter 中称为路由(route))。您将学习如何在主路由和新路由之间导航(切换页面)。

在 Flutter 中,导航器管理应用程序的路由栈。将路由推入(push)到导航器的栈中,将会显示更新为该路由页面。从导航器的栈中弹出(pop)路由,将显示返回到前一个路由。

1. 在 RandomWordsState 的 build 办法中为 AppBar 增加一个列表图标。当用户点击列表图标时,蕴含收藏夹的新路由页面入栈显示。

提醒: 某些 widget 属性须要单个 widget(child),而其它一些属性,如 action,须要一组 widgets(children),用方括号 [] 示意。

将该图标及其相应的操作增加到 build 办法中:

classRandomWordsStateextendsState<RandomWords>{
...
@override
  Widget build(BuildContext context){
returnnewScaffold(
      appBar:newAppBar(title:newText('Startup Name Generator'),
actions:<Widget>[new IconButton(icon:new Icon(Icons.list), onPressed: _pushSaved),
],
),
      body:_buildSuggestions(),);
}
...}

2. 向 RandomWordsState 类增加一个 _pushSaved() 办法.

classRandomWordsStateextendsState<RandomWords>{
...
void_pushSaved(){}}

热重载利用,列表图标将会呈现在导航栏中。当初点击它不会有任何反馈,因为 _pushSaved 函数还是空的。

3. 当用户点击导航栏中的列表图标时,建设一个路由并将其推入到导航管理器栈中。此操作会切换页面以显示新路由。

新页面的内容在在 MaterialPageRoute 的 builder 属性中构建,builder 是一个匿名函数。

增加 Navigator.push 调用,这会使路由入栈(当前路由入栈均指推入到导航管理器的栈)

void_pushSaved(){Navigator.of(context).push();}

4. 增加 MaterialPageRoute 及其 builder。当初,增加生成 ListTile 行的代码。ListTile 的 divideTiles()办法在每个 ListTile 之间增加 1 像素的分割线。该 divided 变量持有最终的列表项。

void_pushSaved(){Navigator.of(context).push(
new MaterialPageRoute(builder:(context){
final tiles = _saved.map((pair){
returnnew ListTile(
title:new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final divided = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList();},
),
);}

5.builder 返回一个 Scaffold,其中蕴含名为“Saved Suggestions”的新路由的利用栏。新路由的 body 由蕴含 ListTiles 行的 ListView 组成; 每行之间通过一个分隔线分隔。
增加如下高亮的代码:

void_pushSaved(){Navigator.of(context).push(
newMaterialPageRoute(builder:(context){
final tiles = _saved.map((pair){
returnnewListTile(
              title:newText(
                pair.asPascalCase,
                style: _biggerFont,
),
);
},
);
final divided = ListTile
.divideTiles(
            context: context,
            tiles: tiles,
)
.toList();

returnnew Scaffold(
appBar:new AppBar(title:new Text('Saved Suggestions'),
),
body:new ListView(children: divided),
);
},
),
);}

5. 热重载应用程序。珍藏一些选项,并点击利用栏中的列表图标,在新路由页面中显示珍藏的内容。请留神,导航器会在利用栏中增加一个“返回”按钮。你不用显式实现 Navigator.pop。点击后退按钮返回到主页路由。

遇到了问题?

如果您的利用不能失常工作,请参考上面链接处的代码,比照并更正。

· lib/main.dart

第 7 步:应用主题更改 UI

在这最初一步中,您将会应用主题。主题管制您应用程序的外观和格调。您能够应用默认主题,该主题取决于物理设施或模拟器,也能够自定义主题以适应您的品牌。

1. 您能够通过配置 ThemeData 类轻松更改应用程序的主题。您的应用程序目前应用默认主题,上面将更改 primary color 色彩为红色。

通过如下高亮局部代码,将应用程序的主题更改为红色:

classMyAppextendsStatelessWidget{

@override

Widget build(BuildContext context){

returnnewMaterialApp(

      title:'Startup Name Generator',

theme:new ThemeData(primaryColor: Colors.white,),

      home:newRandomWords(),);

}}

2. 热重载利用。请留神,整个背景将会变为红色,包含利用栏。

3. 作为读者的一个练习,应用 ThemeData 来扭转 UI 的其余方面。Material library 中的 Colors 类提供了许多能够应用的色彩常量,你能够应用热重载来疾速简略地尝试、试验。

遇到了问题?

如果你遇到了问题,请查看以下链接中应用程序的最终代码。

· lib/main.dart

结语

因为文章篇幅无限,仅展现一部分内容,此份笔记还蕴含 Flutter 开发环境搭建和调试、Dart 语法篇之汇合的应用与源码解析、Dart 语法篇之汇合操作符函数与源码剖析等等。

敌人们如果有须要,能够我的【Github】浏览下载.

退出移动版