美文网首页
Focus相关

Focus相关

作者: liboxiang | 来源:发表于2020-04-23 16:11 被阅读0次

    备注:文中忽略了部分逻辑的,该文只是为了理解focus和unfocus过程,及怎么显示键盘和收起键盘的

    focus.png

    EditableText

    Focus相关的类都是配合EditableText使用的

    ///EditableTextState class
     bool get _hasFocus => widget.focusNode.hasFocus;
    

    由上面的流程图可以知道,EditableTextState initState的时候会监听widget.focusNode,当接收到通知的时候最终会调用_openOrCloseInputConnectionIfNeeded方法。在_openOrCloseInputConnectionIfNeeded方法内会判断_hasFocus,然后调用_openInputConnection()_closeInputConnectionIfNeeded()

    • _openInputConnection()会调用TextInputConnect的show(),然后调用TextInput的_show。最终会通过channel调起原生代码显示键盘
    • _closeInputConnectionIfNeeded()原理类似,最终会通过channel调起原生代码收起键盘

    Focus相关

    widget

    • class Focus extends StatefulWidget,node对应的是FocusNode。一个小部件,它管理[FocusNode]以允许将键盘焦点赋予该小部件及其后代。
    • class FocusScope extends Focus,node对应的是FocusScopeNode。FocusScope与Focus类似,但也可以作为其他Focus和FocusScope的边界将它们分组在一起。

    两者的state的build方法中都会调用_focusAttachment.reparent();以将FocusNode和前面的node树连接起来。同时,两者的state的build方法中都使用到class _FocusMarker extends InheritedNotifier<FocusNode>
    Focus和FocusScope的InheritedWidget标记。

    reparent

    由上面流程图可知,在EditableTextState的build方法中会调用FocusAttachment的reparent方法,将最近_FocusMarker中的FocusNode或者BuildOwner中focusManager的rootScope设置为node的parent,则将parent赋值给node._parent,并将node添加到parent的_children数组中。
    由以上流程图可知,调用this.requestFocus(focusNode)方法,会将this设置为focusNode的parent。

    requestFocus->_doRequestFocus

    由流程图可知,对于FocusNode和FocusScopeNode,调用requestFocus方法,最终是分别调用各自的_doRequestFocus方法。_doRequestFocus方法中各自的逻辑如下:

    • FocusNode :调用_setAsFocusdChild方法,该方法的效果就如下图琐事,从图一变化到图二:


      图1
      图2.png

      总结起来就是将this层级上的所有FocusScopeNode分别放置到各自上一级FocusScopeNode的_focusedChildren数组中最后面。则设置为focusedChild值

    ///FocusScopeNode class
    FocusNode get focusedChild {
        assert(_focusedChildren.isEmpty || _focusedChildren.last.enclosingScope == this, 'Focused child does not have the same idea of its enclosing scope as the scope does.');
        return _focusedChildren.isNotEmpty ? _focusedChildren.last : null;
      }
    

    同时会调用_markAsDirty方法,在该方法内调node的_notify方法或者调_manager的_markNeedsUpdate

    • FocusScopeNode:查找最近的非FocusScopeNode类型的focusedChild(应该就是FocusNode类型)调用_doRequestFocus方法,如果没有则尝试聚焦最后一个FocusScopeNode

    FocusManager

    ///当前focus的node
    FocusNode get primaryFocus => _primaryFocus;
    FocusNode _primaryFocus;
    ///请求focus,但是还没有focus的node
    FocusNode _nextFocus;
    

    由以上流程图可知,当focus的时候,会先将请求focus的node传递给_nextFocus,让后在调用node._notify()之前将_nextFocus赋值给_primaryFocus,并将_nextFocus置空。
    当unfocus的时候,会将_primaryFocus和_nextFocus都置空,同时还会调用node._notify()

    相关文章

      网友评论

          本文标题:Focus相关

          本文链接:https://www.haomeiwen.com/subject/gmlxbhtx.html