flutter中萬物皆組件,組件皆有key,flutter開發是組件堆砌的,組件很多,能複用就複用,如果沒有一個標記,flutter做diff算法複用element的時候很容易數據錯亂,所以,key根本作用在這
key能解決大部分的問題,flutter能分清key對應的元素。但是別指望能解決所有的問題。下面逐個解析,綜合應用key解決所有問題
比如:
center(container(text("", key)))這種結構,使用和不使用center的情況下內部的text就複用不了了
Widget和ELement
widget是虛擬的,並不是實際渲染的那個東西
flutter中有widget tree,element tree,renderobject tree。widget tree可以理解爲藍圖,一個佈局頁面的工具,element tree管理狀態,上能訪問widget tree,下能關聯renderobject tree。
diff算法:flutter需要刷新頁面佈局的時候,會從要刷新的Element tree第一級逐級往下對比:widget tree 和 element tree對比,判斷類型是否改變 & 判斷key是否一致。如果有一個條件不滿足,就在當前widget tree同級別組件中找同類型同key的組件關聯
針對element tree在widget tree關聯不到的,會銷燬實例。widget tree中在element tree中沒有的,element tree會新建並關聯上
懂了這個複用流程後,上面說的那個有沒有center的情況就能解釋了。
局部鍵
ValueKey
flutter對比key的規則是值是否相等,這個可以自己重寫operator
class MyValueKey {
String id;
String key;
MyValueKey(this.id, this.key);
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is MyValueKey &&
runtimeType == other.runtimeType &&
id == other.id &&
key == other.key;
@override
int get hashCode => id.hashCode ^ key.hashCode;
}
generate快速生成
ObjectKey
key的對比規則是對比key的內存地址,是否是同一個obj,而不是單單看值。跟java中的equals和==的區別差不多。
/// Check whether two references are to the same object.
///
/// Example:
/// ```dart
/// var o = new Object();
/// var isIdentical = identical(o, new Object()); // false, different objects.
/// isIdentical = identical(o, o); // true, same object
/// isIdentical = identical(const Object(), const Object()); // true, const canonicalizes
/// isIdentical = identical([1], [1]); // false
/// isIdentical = identical(const [1], const [1]); // true
/// isIdentical = identical(const [1], const [2]); // false
/// isIdentical = identical(2, 1 + 1); // true, integers canonicalizes
/// ```
external bool identical(Object? a, Object? b);
UniqueKey
組件每次刷新時候,UniqueKey都會是新的,這種key用的不多,可以理解一下下面的代碼場景:
return Center(
child: AnimatedSwitcher(
duration: const Duration(seconds: 1),
child: Text("content", key: UniqueKey(),),
),
);
這種應用,當content有變化的時候會有動畫過渡。每次content有變動觸發刷新,uniqueKey都不一樣,text就會新建
全局鍵
上面有說當使用局部鍵的時候,如果widget tree層級有變化,那麼狀態就會丟失,但是這種情況怎麼解決呢?
可以使用GlobalKey,跟普通的key使用一樣
注意:
1、globalKey在app中是唯一的,一個GlobalKey實例只能給一個組件使用。所以,需要幾個實例化幾個
根據globalKey找組件
前端:document.getElementById
iOS:getViewWithTag
android:findViewById
應用都差不多
_globalKey.currentState as yourWidgetState
_globalKey.currentWidget as yourWidget
_globalKey.currentContext as RenderBox