前语
最近闲下来在回顾常识点的时分,发现用了很久的Get.context
却并不知道它的详细完成逻辑,和GlobalKey
获取的BuildContext
的方法又有什么共同点和差异点。今天就来剖析一下它们。
GlobalKey的完成
@optionalTypeArgs
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
factory GlobalKey({ String? debugLabel }) => LabeledGlobalKey<T>(debugLabel);
const GlobalKey.constructor() : super.empty();
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
BuildContext? get currentContext => _currentElement;
Widget? get currentWidget => _currentElement?.widget;
T? get currentState {
final Element? element = _currentElement;
if (element is StatefulElement) {
final StatefulElement statefulElement = element;
final State state = statefulElement.state;
if (state is T) {
return state;
}
}
return null;
}
}
GlobalKey
是一个抽象类,咱们创立的GlobalKey
实践回来的是LabeledGlobalKey
,这儿咱们不去探究。
GlobalKey
内部完成十分简单,供给了三个getter
,这儿咱们要探究的是currentContext
。
currentContext从何而来
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
BuildContext? get currentContext => _currentElement;
能够看到currentContext
获取的是_currentElement
,_currentElement
又是从_globalKeyRegistry
中获取的传入当时this
目标。
class BuildOwner {
final Map<GlobalKey, Element> _globalKeyRegistry = <GlobalKey, Element>{};
void _registerGlobalKey(GlobalKey key, Element element) {
_globalKeyRegistry[key] = element;
}
void _unregisterGlobalKey(GlobalKey key, Element element) {
if (_globalKeyRegistry[key] == element) {
_globalKeyRegistry.remove(key);
}
}
}
能够看到在BuildOwner
关于_globakKeyRegistry
的完成也很简单,一个GlobalKey
做key
,Element
做value
的map
,供给了增加
与移除
的办法。这两个办法又是何时调用的呢。
GlobalKey增加、撤销
咱们都知道Globalkey
是作为key
传入Widget
的,咱们随意找一个Widget
一探究竟。
abstract class StatefulWidget extends Widget {
const StatefulWidget({ super.key });
}
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
}
咱们在Widget
传入的key
终究会赋值给Widget
,而Widget
仅仅作为配置项终究创立的是Element
,所以咱们进入Element
检查。
abstract class Element extends DiagnosticableTree implements BuildContext {
void mount(Element? parent, Object? newSlot) {
if (parent != null) {
_owner = parent.owner;
}
final Key? key = widget.key;
if (key is GlobalKey) {
owner!._registerGlobalKey(key, this);
}
}
void unmount() {
final Key? key = _widget?.key;
if (key is GlobalKey) {
owner!._unregisterGlobalKey(key, this);
}
}
去掉无关代码,ELement
中增加
和移除GlobalKey
的当地有两处,mount
挂载和unmount
撤销挂载,只有传入的key
为GlobalKey
时才会履行。
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
BuildContext? get currentContext => _currentElement;
}
再回过头来看GlobalKey
内部完成,就能理解GlobakKey
是怎样拿到当时当时BuildContext
的了。
Get.context的完成
extension GetNavigation on GetInterface {
GlobalKey<NavigatorState> get key => _getxController.key;
BuildContext? get context => key.currentContext;
static GetMaterialController _getxController = GetMaterialController();
}
点击检查Get.context
源码,咱们能够找到上面三行代码,能够看到Get
获取context
的方法也是用的GlobalKey
,它仅仅对这个方法做了一层封装供咱们运用。
这儿的key
是从GetMaterialController
中获取的,接下来咱们来看看在GetMaterialController
中key
是怎样界说的。
Get中GlobalKey是怎样创立的
class GetMaterialController extends SuperController {
var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default');
GlobalKey<NavigatorState> get key => _key;
GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
_key = newKey;
return key;
}
}
在GetMaterialController
中有一个默许的key
,同时也能调用addKey
替换默许的key
,这个默许的key
又是何时生效的呢。
GlobakKey怎样起作用
咱们把目光放回到main.dart
中,再运用了Get
咱们都会把MaterialApp
替换成GetMaterialApp
,而Get
对MaterialApp
对其做一层封装便是为了履行自己的一系列操作逻辑。
class GetMaterialApp extends StatelessWidget {
final GlobalKey<NavigatorState>? navigatorKey;
const GetMaterialApp({
Key? key,
this.navigatorKey,
});
@override
Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
builder: (_) =>
MaterialApp(
navigatorKey: (navigatorKey == null
? Get.key
: Get.addKey(navigatorKey!)),
)
}
能够看到,在Get
中假如咱们传入了navigatorKey
就调用addKey
替换它的默许key
,假如没有传入就运用Get
的默许key
。
看到这儿咱们也就能理解Get.context
是怎样起作用和获取到了。
总结
-
GloblKey
终究赋值给Widget
、在对应的Element
中调用BuildOwner
进行增加和撤销 -
GlobalKey
获取到的key
是在BuildOwner
中增加时传入的当时Element
-
Get
中有默许的GlobalKey
,在GetMaterialApp
中假如咱们传入了navigatorKey
,就会代替默许的key
-
Get.context
原理便是GlobalKey
,Get
仅仅对这种方法的一种封装
关于BuildOwner
的常识假如有不了解的,Flutter框架剖析 — runApp初始化里面有对WidgetBinding
和BuildOwner
有的介绍。