這是我參與8月更文挑戰的29天,活動詳情檢視:8月更文挑戰
Flutter Key的原理和使用 (一) 沒有Key會發生什麼 (juejin.cn)
Flutter Key的原理和使用 (二) Widget 和 Element 的對應關係 (juejin.cn)
我們在上一章說到,同一級中相同型別的Widget
不給它傳Key
的話,Flutter有時候就會出現分不清它們之間的對應關係,尤其是Widget之間的順序發生改變的時候. 此時,我們就需要傳個key給它.
Key的種類
Key有兩個子類:
- LocalKey 區域性鍵,在同一級中要唯一,可以理解為
同級唯一性
- GlobalKey 全域性鍵 , 在整個App中必須是唯一的.
從效能上來講,如果不需要用到GlobalKey的話,儘量不用,LocalKey因為只對比同一級別,因此會快很多.上一章也說過,在父級或者子級是不會需考慮的. 如果違背了上述的唯一性原則,執行時會報錯,提示你Key沒有隻出現一次.
LocalKey
而LocalKey又有3個子類
- ValueKey
- ObjectKey
- UniqueKey
其實當你的Widget全都是StatelessWidget的時候,不需要用到Key,只有當使用Statefuldiget的時候才有可能用到key.
ValueKey
const ValueKey(this.value)
final T value;
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
return false;
return other is ValueKey<T>
&& other.value == value;
}
複製程式碼
它的構造方法很簡單,有一個value,型別是T,也就是隨便你想傳什麼都可以.當然因為唯一性原則,同級中Valukey的value是不能相同的.這個可以看它的operator
方法.
ObjectKey
const ObjectKey(this.value);
final Object? value;
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
return false;
return other is ObjectKey
&& identical(other.value, value);
}
複製程式碼
ObjectKey跟ValueKey大同小異,我們主要看一下區別,value
的型別從T變成了Object,operator
方法也不一樣.
identical
對比是否是相等或者說相同的時候,它其實屬於對比引用或者說指標是否相等,類似於Java中對比記憶體地址.
我們建立一個稍微複雜一點的類看一下二者實際的區別:
class People{
final String name;
final int age;
People(this.name, this.age);
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is People && runtimeType == other.runtimeType && name == other.name && age == other.age;
@override
int get hashCode => name.hashCode ^ age.hashCode;
}
複製程式碼
主要看一下operator
方法,當年齡相等並且姓名相等時,就判斷是相等的.
此時如果程式碼是這樣的話:
Box(Colors.red, key: ValueKey(People('a', 18))),
Box(Colors.red, key: ValueKey(People('a', 18))),
複製程式碼
執行之後,
啊,果不其然,報錯了. 然後我們換成ObjectKey試試:
這就是因為People('a', 18)
是new出來的新物件(在dart中,new關鍵字是可以被省略的),flutter判斷二者不是同一個物件,因為對應的ObjectKey也不相等.
這就是ObjectKey跟ValueKey的主要區別.
UniqueKey
class UniqueKey extends LocalKey {
UniqueKey();
@override
String toString() => '[#${shortHash(this)}]';
}
複製程式碼
顧名思義,UniqueKey
是一個獨一無二的Key,也就是說它只和自己相等.因此UniqueKey()
和UniqueKey()
是不相等的.
可以看到,換成UniqueKey之後,再進行hot reload,發現狀態丟失了,因為Key
變了, 新的UniqueKey和舊的是不相等的.所以state就沒有辦法保留下來.
那麼問題來了, 這玩意到底有啥用?
其實,丟失狀態
就是它的一種用法,一般在動畫效果中會用到.
另外就是它不需要value
,當你不想傳個value的時候,像我經常有起名頭疼
的毛病,需要key的時候,這個value該傳什麼值, 我得想一會,可能還想不好,索性不傳了,此時可以使用UniqueKey.
那就又有個問題,它每次都會丟掉狀態啊,不是我們希望的,怎麼辦?
把UniqueKey定義到build的外部,比如
final keyRed = UniqueKey();
final keyBlue = UniqueKey();
複製程式碼
因為是一開始就new出來的兩個Key,所以在使用的時候,keyRed是沒有改變的,也就達到了我們的目的.
GlobalKey
ok,接下來說到GlobalKey , 因為標題的原因啊,我們下一章再講它.