Flutter - 无法在路线之间保持焦点

Posted

技术标签:

【中文标题】Flutter - 无法在路线之间保持焦点【英文标题】:Flutter - Trouble preserving focus between routes 【发布时间】:2019-01-31 23:34:24 【问题描述】:

我有一个表单,它使用FocusNodes 直观地指示表单的哪个部分处于活动状态。一个字段将 PopupRoute 扩展为一种弹出“键盘”。我的问题是,当我按下该字段时,键盘会弹出,但焦点的视觉效果不会出现。

来自FocusNode 的侦听器的一些调试显示它获得焦点但立即失去焦点。我想是因为新的PopupRoute有了新的FocusScopeNode,所以我的FocusNode没有焦点了。

如何在另一条路线上保持该领域的焦点?我试过了:

在所有构建方法中使用FocusScope.of(context).reparentIfNeeded(focusNode),但没有做任何事情(我不太了解这个函数tbh) 将当前的FocusScope.of(context) 传递给我的自定义PopupRoute 以供使用。这确实有效,但弹出后,我无法再集中注意力(我猜它被丢弃了?)

代码方面,我在现场点击时调用requestFocus,并在 initState 中添加此侦听器:

    widget.focusNode.addListener(() 
      print(widget.focusNode);
      if (widget.focusNode.hasFocus) 
        Navigator.of(context).push(
          CustomKeyboardPopupRoute(
            state: widget.state,
            position: //position stuff,
            focusScopeNode: FocusScope.of(context), //the second of my ideas which didn't quite work above
          )
        ).then((_) 
           widget.focusNode.unfocus();
        );
    ); 

【问题讨论】:

【参考方案1】:

你走在正确的轨道上,确实这是因为FocusScopeNode

让你的键盘路由扩展TransitionRoute:

class CustomKeyboardPopupRoute extends TransitionRoute 
  @override
  bool get opaque => false;

  @override
  Duration get transitionDuration => Duration(milliseconds: 300);

  @override
  Iterable<OverlayEntry> createOverlayEntries() sync* 
    yield OverlayEntry(
      opaque: false,
      maintainState: true,
      builder: _buildKeyboard,
    );
  

  Widget _buildKeyboard(BuildContext context) 
    final positionAnimation = Tween(begin: Offset(0.0, 1.0), end: Offset.zero).animate(animation);
    return SlideTransition(position: positionAnimation, child: Align(
      alignment: Alignment.bottomCenter,
      child: ...
    ),);
  

【讨论】:

太棒了,谢谢!通过yieldModalBarrier 之前_buildKeyboard 我不明白这个答案。自定义过渡如何与 FocusScope 有任何关系?抄送@卢卡斯 过渡与它没有任何关系。但是当您定义自定义路线时,您必须注意转换。这个答案的重点:如果您想将焦点保持在父路由的TextField 上,则不能将PopupRoute 用于自定义键盘。 它们以不同的方式扩展父类,其中一个区别是PopupRoute 创建了一个新的FocusScopeNodeTransitionRoute 没有。【参考方案2】:

非常感谢。

Iterable<OverlayEntry> createOverlayEntries() sync* 
    yield OverlayEntry(
      opaque: false,
      maintainState: true,
      builder: (content) 
        return ModalBarrier(dismissible: true);
      
    );
    yield OverlayEntry(
      opaque: false,
      maintainState: true,
      builder: _buildContent,
    );
  

【讨论】:

以上是关于Flutter - 无法在路线之间保持焦点的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 12 个小技巧

Flutter Mobile 或 Web 应用程序之间有啥区别?

Flutter Xcode build failed 错误无法生成进程

使用 FocusScopeNode 在 TextFormFields 之间轻松移动焦点

热修复生态混合工程 | Flutter 2019 产品路线图正式公布

Cocos2D v3 CCParallaxNode 滚动无法让玩家保持焦点