theme: cyanosis
前言
Fluter 2.0 已經(jīng)發(fā)布了一段時(shí)間了,其中一項(xiàng)就是包含 Dart 2.12 的穩(wěn)定版,完全支持空安全聲明。作為一個(gè)進(jìn)步的 Flutter 組織
, 組織的小伙伴也在第一時(shí)間支持了空安全。
組織發(fā)布的組件: https://pub.flutter-io.cn/publishers/fluttercandies.com/packages
組織支持空安全的進(jìn)度: https://github.com/fluttercandies/flutter_candies/issues/5
介紹
以下的組件均已支持空安全,這里只會(huì)做簡單的介紹,具體使用方法,請到各組件下地址查看。
屏幕適配
Adaptation,用于屏幕適配的組件,你只需要設(shè)置設(shè)計(jì)稿的寬度,其他的尺寸直接按照設(shè)計(jì)稿填寫即可。當(dāng)然這種適配方式其實(shí)是不推薦的,正如作者所言。
用戶使用更大的屏幕是為了接收更多的信息, 而不是看到更大的字
基于這個(gè)觀點(diǎn), 我個(gè)人建議使用文字流式, 圖片寬高比, 控件彈性的方案來做
但是很多初學(xué)者對(duì)于這個(gè)原則很難把握, 而等比例放大比較容易理解, 所以我寫了這個(gè)庫
import 'package:adaptation/adaptation.dart';
MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
builder: (context, widget) {
return Adaptation(
child: widget,
designWidth: 375, // 你的設(shè)計(jì)稿寬度
);
},
);
資源文件生成
assets_generator,用于自動(dòng)生成 assets 配置 (yaml) 以及 consts 的工具,支持單項(xiàng)目和多模塊。
-h, --[no-]help 顯示幫助信息
-p, --path Flutter 項(xiàng)目的根路徑
(默認(rèn) ".")
-f, --folder assets 文件夾的名字
(默認(rèn) "assets")
-w, --[no-]watch 是否繼續(xù)監(jiān)聽 assets 的變化
(默認(rèn) 開啟)
-t, --type pubsepec.yaml 生成配置的類型
"d" 代表以文件夾方式生成 "- assets/images/"
"f" 代表以文件方式生成 "- assets/images/xxx.jpg"
(默認(rèn) "d")
-s, --[no-]save 是否保存命令到本地
如果執(zhí)行 "agen" 不帶任何命令,將優(yōu)先使用本地的命令進(jìn)行執(zhí)行
-o, --out const 類放置的位置
(默認(rèn)放置在 "lib" 下面)
-r, --rule consts 的名字的命名規(guī)范
"lwu"(小寫帶下劃線) : "assets_images_xxx_jpg"
"uwu"(大寫帶下劃線) : "ASSETS_IMAGES_XXX_JPG"
"lcc"(小駝峰) : "assetsImagesXxxJpg"
(默認(rèn) "lwu")
-c, --class const 類的名字
(默認(rèn) "Assets")
--const-ignore 使用正則表達(dá)式忽略一些const(不是全部const都希望生成)
圖片
ExtendedImage,集眾多功能為一體的圖片組件,包括以下主要功能:
- 緩存網(wǎng)絡(luò)圖片
- 加載狀態(tài)(正在加載,完成,失敗)
- 拖拽縮放圖片
- 圖片編輯(裁剪,旋轉(zhuǎn),翻轉(zhuǎn))
- 圖片預(yù)覽(跟微信掘金一樣)
- 滑動(dòng)退出效果(跟微信掘金一樣)
- 設(shè)置圓角,邊框
- 支持進(jìn)度顯示
- 圖片預(yù)覽上滑顯示詳情(跟圖蟲一樣)
- 減少內(nèi)存占用
zoom.gif
|
slide.gif
|
![]() photo_view.gif
|
![]() editor.gif
| ||
9e93eba3cc614ddbb818a3a445a41a99_tplv-k3u1fbpfcp-zoom-1 (1).gif
|
2097626b7d0a406ab769cb528a31388e_tplv-k3u1fbpfcp-zoom-1.gif
|
列表擴(kuò)展
ExtendedList,針對(duì)官方
Listview 和 GirdView 做的擴(kuò)展組件,包括以下主要功能:
- 監(jiān)聽元素回收
- 監(jiān)聽
Viewport中元素變化 - 為最后一個(gè)元素設(shè)置特殊布局
- 列表倒序特殊布局,類聊天列表
gridview.gif
|
chat_list.gif
|
嵌套滾動(dòng)視圖擴(kuò)展
ExtendedNestedScrollView,主要解決官方 NestedScrollView 存在的2個(gè)問題。
- 解決
NestedScrollView的 Header 中不能處理多個(gè)pinned為true的元素的問題。https://github.com/flutter/flutter/issues/22393 - 解決
NestedScrollView的 Body 中列表滾動(dòng)會(huì)互相影響的問題。https://github.com/flutter/flutter/issues/21868
Sliver 擴(kuò)展
ExtendedSliver,對(duì) Sliver 組件的擴(kuò)展,主要包括以下功能:
-
SliverPinnedPersistentHeader,跟官方的SliverPersistentHeader(pinned: true)一樣的效果, 不同的是你不需要去設(shè)置minExtent和maxExtent。因?yàn)榇蟛糠謭鼍跋旅?,我們是無法提前知道minExtent和maxExtent。 -
SliverPinnedToBoxAdapter,可以通過它輕松創(chuàng)建一個(gè)置頂?shù)脑?,?dāng)child沒有layout之前,你沒法知道child的實(shí)際大小,這將是非常有用的組件。 -
ExtendedSliverAppbar,你可以創(chuàng)建一個(gè)跟SliverAppbar一樣效果的組件,而不用去關(guān)心expandedHeight。
TabBarView 擴(kuò)展
ExtendedTabs,對(duì) TabBarView 組件的擴(kuò)展,主要包括以下功能:
- 解決多級(jí)
TabBarView嵌套的時(shí)候,無法連貫切換的問題 - 垂直方向滾動(dòng)
- 設(shè)置緩存頁面數(shù)量
- 提供
CarouselIndicator和ColorTabIndicator
link.gif
|
scrollDirection.gif
|
文本
ExtendedText,針對(duì) Text 組件的擴(kuò)展,主要包括以下功能:
- 方便快速生成特殊文本,將字符串轉(zhuǎn)換成特定的
InlineSpan。 -
BackgroundTextSpan自定文字背景,處理圓角或者中英文背景高度不一致的問題。 -
ExtendedWidgetSpan支持選擇和復(fù)制, https://github.com/flutter/flutter/issues/38474 . -
TextOverflowWidget自定義文本溢出效果, https://github.com/flutter/flutter/issues/26748 。
special_text.jpg
|
overflow.jpg
|
background.png
|
selection.gif
|
輸入框
ExtendedTextField,針對(duì) TextField 組件的擴(kuò)展,主要包括以下功能:
- 方便快速生成特殊文本,原理很簡單,就是把字符串轉(zhuǎn)換成特定的
InlineSpan。 -
ExtendedWidgetSpan支持輸入框中插入任何Widget,比如表情圖片。 -
ExtendedWidgetSpan支持選擇和復(fù)制, https://github.com/flutter/flutter/issues/30688 。
![]() extended_text_field.gif
| |
![]() extended_text_field_image.gif
| |
custom_toolbar.gif
|
widget_span.gif
|
路由注解
ff_annotation_route,通過注解生成路由映射,統(tǒng)一處理路由,支持 Navigator 1.0 和 Navigator 2.0。
- 激活工具
pub global activate ff_annotation_route - 增加引用
dependencies:
# 在子模塊中引入
ff_annotation_route_core: any
# 在根項(xiàng)目引入,包括一些幫助類以及 ff_annotation_route_core
ff_annotation_route_library: any
- 添加注釋
工具會(huì)自動(dòng)處理帶參數(shù)的構(gòu)造,不需要做特殊處理。唯一需要注意的是,你需要設(shè)置 argumentImports 來為 class/enum 的參數(shù)提供 import 地址?,F(xiàn)在你也可以使用 @FFArgumentImport() 注釋來替代.
@FFArgumentImport('hide TestMode2')
import 'package:example1/src/model/test_model.dart';
@FFArgumentImport()
import 'package:example1/src/model/test_model1.dart' hide TestMode3;
import 'package:ff_annotation_route_library/ff_annotation_route_library.dart';
@FFRoute(
name: 'flutterCandies://testPageE',
routeName: 'testPageE',
description: 'Show how to push new page with arguments(class)',
// argumentImports are still work for some cases which you can't use @FFArgumentImport()
// argumentImports: <String>[
// 'import \'package:example1/src/model/test_model.dart\';',
// 'import \'package:example1/src/model/test_model1.dart\';',
// ],
exts: <String, dynamic>{
'group': 'Complex',
'order': 1,
},
)
class TestPageE extends StatelessWidget {
const TestPageE({
this.testMode = const TestMode(
id: 2,
isTest: false,
),
this.testMode1,
});
factory TestPageE.deafult() => TestPageE(
testMode: TestMode.deafult(),
);
factory TestPageE.required({@required TestMode testMode}) => TestPageE(
testMode: testMode,
);
final TestMode testMode;
final TestMode1 testMode1;
}
- 執(zhí)行命令生成路由,
ff_route <command> [arguments],全部命令如下:
-h, --[no-]help 幫助信息。
-p, --path 執(zhí)行命令的目錄,默認(rèn)當(dāng)前目錄。
-o, --output route 和 helper 文件的輸出目錄路徑,路徑相對(duì)于主項(xiàng)目的 lib 文件夾。
-n, --name 路由常量類的名稱,默認(rèn)為 `Routes`。
-g, --git 掃描 git 引用的 package,你需要指定 package 的名字,多個(gè)用 `,` 分開
--routes-file-output routes 文件的輸出目錄路徑,路徑相對(duì)于主項(xiàng)目的lib文件夾
--const-ignore 使用正則表達(dá)式忽略一些const(不是全部const都希望生成)
--[no-]route-constants 是否在根項(xiàng)目中的 `xxx_route.dart` 生成全部路由的靜態(tài)常量
--[no-]package 這個(gè)是否是一個(gè) package
--[no-]supper-arguments 是否生成路由參數(shù)幫助類
-s, --[no-]save 是否保存命令到本地。如果保存了,下一次就只需要執(zhí)行 `ff_route` 就可以了。
--[no-]null-safety 是否支持空安全,默認(rèn) `true`
- 設(shè)置
MaterialApp的onGenerateRoute回調(diào)
import 'package:ff_annotation_route_library/ff_annotation_route_library.dart';
import 'package:flutter/material.dart';
import 'example_route.dart';
import 'example_routes.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ff_annotation_route demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: Routes.fluttercandiesMainpage,
onGenerateRoute: (RouteSettings settings) {
return onGenerateRoute(
settings: settings,
getRouteSettings: getRouteSettings,
routeSettingsWrapper: (FFRouteSettings ffRouteSettings) {
if (ffRouteSettings.name == Routes.fluttercandiesMainpage ||
ffRouteSettings.name ==
Routes.fluttercandiesDemogrouppage.name) {
return ffRouteSettings;
}
return ffRouteSettings.copyWith(
widget: CommonWidget(
child: ffRouteSettings.widget,
title: ffRouteSettings.routeName,
));
},
);
},
);
}
}
- 打開一個(gè)頁面
Navigator.pushNamed(
context,
Routes.flutterCandiesTestPageE.name,
arguments: Routes.flutterCandiesTestPageE.requiredC(
testMode: const TestMode(
id: 100,
isTest: true,
),
),
);
可拖拽容器
DraggableContainer,可拖拽容器,支持元素移動(dòng)動(dòng)畫效果,主要包括以下功能:
- 可拖動(dòng)子元素
- 可刪除子元素
- 可固定子元素
- 元素移動(dòng)動(dòng)畫效果
圖片編輯
ImageEditor,強(qiáng)大的原生圖片處理庫,主要包括以下功能:
- 裁剪
- 翻轉(zhuǎn)
- 旋轉(zhuǎn)
- 縮放
- 色彩矩陣變化
- 添加文字
- 混合圖片
- 添加任意圖形

Dialog
SmartDialog,一種更優(yōu)雅的Dialog 解決方案,主要解決了系統(tǒng)自帶的Dialog的一些問題:
- 必須傳 BuildContext。
- 無法穿透暗色背景,點(diǎn)擊 Dialog 后面的頁面。
- 解決系統(tǒng)自帶 Dialog 寫成的 Loading 彈窗,在網(wǎng)絡(luò)請求和跳轉(zhuǎn)頁面的情況,會(huì)存在路由混亂的情況。
資源選擇器
AssetPicker,對(duì)標(biāo)微信的多選資源選擇器,99%接近于原生微信的操作,主要包括以下功能:
- ?? 支持基于代理重載的全量自定義
- ?? 99% 的微信風(fēng)格
- ?? 圖片資源支持
- ??HEIC 格式圖片支持
- ?? 視頻資源支持
- ?? 音頻資源支持
- 1?? 單資源模式
- ?? 國際化支持
- ? 特殊 widget 構(gòu)建支持(前置/后置)
- ?? 自定義路徑排序支持
- ?? 自定義文本構(gòu)建支持
- ? 自定義篩選規(guī)則支持(
photo_manager) - ?? 完整的自定義主題
- ?? 支持 MacOS
1
|
2
|
3
|
|---|---|---|
4
|
5
|
6
|
7
|
8
|
9
|
相機(jī)資源選擇器
CameraPicker,對(duì)標(biāo)微信的視頻資源選擇器,99%接近于原生微信的操作,主要包括以下功能:
- ?? 支持健全的空安全
- ?? 99% 的微信風(fēng)格
- ?? 支持拍照
- ?? 支持設(shè)置曝光參數(shù)
- ??? 支持捏合縮放
- ?? 支持錄像
- ? 支持限制錄像時(shí)間
- ?? 支持錄像時(shí)縮放
- ?? 支持自定義前景 widget 構(gòu)建
image
|
image
|
|---|---|
image
|
image
|
JsonToDart
JsonToDart,強(qiáng)大的 JsonToDart 工具,主要包括以下功能:
- 空安全
- 編輯類名,屬性名
- 去重復(fù)類
- Merge 類屬性
- 數(shù)據(jù)數(shù)組保護(hù)
- 屬性命名規(guī)范化,只讀,排序
- 國際化
- 全平臺(tái)
- 智能可空
| 平臺(tái) | 描述 | 地址 |
|---|---|---|
| Windows | Flutter for Windows | https://gitee.com/zmtzawqlp/JsonToDart/releases/ |
| Macos | Flutter for Macos | https://gitee.com/zmtzawqlp/JsonToDart/releases/ |
| Web | Flutter for Web | https://zmtzawqlp.gitee.io/jsontodart/ |
| 微軟商店 | 功能未同步,以后會(huì)替換成 Flutter for UWP | https://www.microsoft.com/store/apps/9NBRW9451QSR |

點(diǎn)贊按鈕
LikeButton,仿推特點(diǎn)贊效果,支持?jǐn)?shù)字動(dòng)畫效果。
增量加載列表
LoadingMoreList,支持各種布局的增量加載列表,主要包括以下功能:
- ListView
- GridView
- 瀑布流
- 多個(gè) Sliver 布局
- 自定義加載狀態(tài) UI
- 監(jiān)控進(jìn)入
Viewport元素 - 類聊天列表布局
- 監(jiān)控元素回收
listview.gif
|
![]() multiple_sliver.gif
|
|
error.gif
| ||
custom_indicator.gif
|
![]() nested_scrollView.gif
|
|
known_sized.gif
|
下拉刷新
PullToRefreshNotification,靈活的自定義下拉刷新組件,可以創(chuàng)造出任意的下拉刷新樣式。
appbar.gif
|
header.gif
|
image.gif
|
candies.gif
|
底部擴(kuò)散模糊動(dòng)畫
RippleBackdropAnimatePage,騷氣十足的模糊動(dòng)畫,只需要幾行代碼就能幫你實(shí)現(xiàn)。
彈出菜單
WPopupMenu,目前最好用的仿微信聊天長按彈出框。
瀑布流
WaterfallFlow,高性能的瀑布流布局,https://github.com/flutter/flutter/issues/40856 。
- 高性能
- 易上手,跟
GridView一樣的api - 可監(jiān)控進(jìn)入
Viewport元素 - 可監(jiān)控元素回收
random_sized.gif
|
custom_scrollView.gif
|
known_sized.gif
|
variable_sized.gif
|
遷移
指南
感謝 Flutter & Dart 文檔中國本地化 全球遮天團(tuán) 為我們提供了完整準(zhǔn)確的文檔,https://dart.cn/null-safety/migration-guide ,空安全 遷移大概有下面幾個(gè)步驟:
執(zhí)行
flutter pub outdated --mode=null-safety,檢查自己項(xiàng)目依賴的庫是否都支持空安全。如果都支持了,執(zhí)行
dart migrate --apply-changes。不加--apply-changes的話,會(huì)有一個(gè)瀏覽器地址,你打開之后,可以在瀏覽器中進(jìn)行修改。我一般還是習(xí)慣在直接--apply-changes之后直接在vscode中進(jìn)行修改。執(zhí)行完畢之后,你的Dart SDK版本會(huì)自動(dòng)改為大于2.12.0。(注意,執(zhí)行 dart migrate 命令必須確保SDK是小于2.12.0的)
environment:
sdk: '>=2.12.0 <3.0.0'
- 工具不是萬能的,會(huì)有一些
錯(cuò)誤,請先查看完 https://dart.cn/null-safety 之后,根據(jù)自己的業(yè)務(wù)場景對(duì)代碼進(jìn)行更正。
問題
空安全對(duì)非空 List<T> 的影響是非常大的。
不能對(duì)非空的列表設(shè)置更大的長度
List 的 length getter 也有一個(gè)對(duì)應(yīng)的 setter,這一點(diǎn)鮮為人知。您可以對(duì)列表設(shè)置一個(gè)較短的長度,從而截?cái)嗨?。您也可以?duì)列表設(shè)置一個(gè)更長的長度,從而使用未初始化的元素填充它。
如果您對(duì)一個(gè)非空的列表做了這樣的操作,在訪問未初始化的元素時(shí),就與空安全的健全性發(fā)生了沖突。為了防止意外發(fā)生,現(xiàn)在對(duì)一個(gè)非空類型的數(shù)組調(diào)用調(diào)用 length setter, 并且 準(zhǔn)備設(shè)置一個(gè)更長的長度時(shí),會(huì)在運(yùn)行時(shí)拋出一個(gè)異常。您仍然可以對(duì)任何類型的列表進(jìn)行截?cái)?,也可以?duì)一個(gè)可空類型的列表進(jìn)行填充。
如果您自定義了列表的類型,例如繼承了 ListBase 或者混入了 ListMixin,那么這項(xiàng)改動(dòng)可能會(huì)造成較大的影響。以上的兩種類型都提供了 insert() 的實(shí)現(xiàn),通過設(shè)置長度,為插入的元素提供空間。在空安全中這樣做可能會(huì)出現(xiàn)錯(cuò)誤,所以我們將它們的 insert() 實(shí)現(xiàn)改為了 add()?,F(xiàn)在您自定義的列表應(yīng)該繼承 add() 方法 方法。
下面我們來跟一波可空列表在做 add 操作時(shí)候的流程,來理解下文檔所說的意思。
| 類 | 位置 |
|---|---|
list.dart |
bin/cache/dart-sdk/lib/collection/list.dart |
growable_array.dart |
bin/cache/dart-sdk/lib/_internal/vm/lib/growable_array.dart |
array.dart |
bin/cache/dart-sdk/lib/_internal/vm/lib/array.dart |
ListMixin.add (dart:collection/list.dart:278)
// List interface.
void add(E element) {
// This implementation only works for lists which allow `null`
// as element.
this[this.length++] = element;
}
List.length= (dart:core-patch/growable_array.dart:227)
void set length(int new_length) {
if (new_length > length) {
// Verify that element type is nullable.
// 官方在這里做了判斷
null as T;
if (new_length > _capacity) {
_grow(new_length);
}
_setLength(new_length);
return;
}
final int new_capacity = new_length;
List._grow (dart:core-patch/growable_array.dart:362)
void _grow(int new_capacity) {
// 創(chuàng)建了一個(gè)長度為 new_capacity 的數(shù)組,并且用 null 填充
var newData = _allocateData(new_capacity);
// This is a work-around for dartbug.com/30090: array-bound-check
// generalization causes excessive deoptimizations because it
// hoists CheckArrayBound(i, ...) out of the loop below and turns it
// into CheckArrayBound(length - 1, ...). Which deoptimizes
// if length == 0. However the loop itself does not execute
// if length == 0.
// 從舊列表中復(fù)制數(shù)據(jù)
if (length > 0) {
for (int i = 0; i < length; i++) {
newData[i] = this[i];
}
}
// 通知引擎替換新數(shù)據(jù)
_setData(newData);
}
-
List._allocateData (dart:core-patch/growable_array.dart:349)以及
_List (dart:core-patch/array.dart.dart:13)
static _List _allocateData(int capacity) {
if (capacity == 0) {
// Use shared empty list as backing.
return _emptyList;
}
// Round up size to the next odd number, since this is free
// because of alignment requirements of the GC.
// (dart:core-patch/array.dart.dart:13)
return new _List(capacity | 1);
}
- 通知引擎更新新數(shù)據(jù)
@pragma("vm:recognized", "graph-intrinsic")
void _setData(_List array) native "GrowableList_setData";
- 通知引擎更新新長度
@pragma("vm:recognized", "graph-intrinsic")
void _setLength(int new_length) native "GrowableList_setLength";
在第三步中,會(huì)返回元素為 null 的列表,所以在空安全的情況下,列表操作中需要做以下改動(dòng)。
List<int> list = List<int>();改為List<int> list = <int>[];List<int> list = List<int>(1);改為List<int> list = List<int>.filled(1, 0);如果你繼承了
ListBase或者混入了ListMixin,你需要重寫add()方法,否則在第二步中就會(huì)報(bào)錯(cuò)。完整代碼
@override
void add(T element) {
_array.add(element);
}
建議
坐和放寬
對(duì)于每次的大版本更新,不要著急升級(jí),特別是你的項(xiàng)目引用了三方組件。三方開源作者是不大可能有時(shí)間立刻就更新,訂閱一下作者的更新計(jì)劃,靜靜等待。一般 stable 版本發(fā)布之后都會(huì)有熱修復(fù)版本。如果你是新手,請坐和放寬,靜待大佬們發(fā)現(xiàn)和解決點(diǎn)一些重大問題之后再更新。
學(xué)會(huì)使用 pub.dev
空安全的組件有很明顯的標(biāo)志 Null safety。打開 Versions 一簽,通過 Min Dart SDK很容易就看出組件是從哪個(gè)版本開始支持空安全的,比如 extended_image 從 3.0.0 版本支持空安全。
另外,有些組件還提供了 Prerelease versions。比如 extended_image 還提供了非空安全版本. 當(dāng)然 Prerelease versions 也可能是預(yù)覽版,修復(fù)緊急問題(一些用戶使用 Flutter master/dev/beta 分支,該分支可能會(huì)有一些 api 的 breaking change),作者會(huì)發(fā)布預(yù)覽版來滿足這部分人群。
每個(gè)人都從萌新而來,愛護(hù)萌新,但也不應(yīng)該縱容巨嬰。
-
https://flutter.cn/ 和 https://dart.cn/ ,從入門到深入,各種資源應(yīng)有盡有。如果你準(zhǔn)備入手
Flutter,這應(yīng)該是你必看的網(wǎng)站。
https://github.com/flutter/flutter/issues ,當(dāng)遇到一些奇怪問題的時(shí)候,可以嘗試搜索官方, 也許地球上某個(gè)地方的我也遇到了相同的問題。如果沒搜到,并且確定是官方的問題,請不要吝嗇你的時(shí)間,提交一個(gè)
issue,讓官方知曉,為其他人節(jié)約時(shí)間,提供思路。不要擔(dān)心你的英文水平,只有多寫,多練習(xí),才能更好。https://www.google.com 和 https://stackoverflow.com 程序猿都應(yīng)該知道和會(huì)使用。
https://juejin.cn 應(yīng)該算是國內(nèi)
Flutter文章最多的一個(gè)網(wǎng)站了,對(duì)于英文不好的小伙伴,有中文的各種各樣的Flutter相關(guān)文章也是極好的。-
qq群:181398081,如果通過上面的方式,你還是沒法解決問題,你可以在
qq群里面提問,很榮幸群里有一群熱心的群友,互相幫助,互相學(xué)習(xí)。 -
最后,不管在哪里提問,盡量上代碼,或者闡明清楚意圖,因?yàn)橐苍S想法或者解決方向從開始就是不正確的。
image
結(jié)語
2歲的糖果
不知不覺,糖果 已經(jīng) 2歲 了,Flutter 也 2.0 了。感謝 糖果 的小伙伴,對(duì)開源組件的持續(xù)支持。從 Flutter Candies 一桶天下 到現(xiàn)在又一年了,組織也在不斷地壯大。歡迎更多的小伙伴都加入進(jìn)來,一起為 Flutter 社區(qū)添磚加瓦。
致糖果們
從 2019年2月14日 孤單一個(gè)人,到現(xiàn)在的 2000 人,感謝每個(gè)糖果的支持,感謝積極回復(fù)問題的糖果們,感謝智能憨憨的群機(jī)器人。如果你喜歡分享,請加入我們;如果你需要?jiǎng)e人的分享,也請加入我們。
愛Flutter,愛糖果
很開心你能閱讀到這里,愛Flutter ,愛糖果 ,歡迎加入 Flutter Candies ,一起生產(chǎn)可愛的 Flutter小糖果








