键盘在显示后立即消失

时间:2019-02-13 07:58:25

标签: dart flutter

我创建了自己的标签实现,因为我需要的功能比当前的标签小部件还多。例如,我在应用程序中有很多向导,其中第2步必须有效,然后才能将第3步导航到第一个。

当TextField位于选项卡中时,它将按预期打开焦点对准的键盘。但是,由于发出了Tab键小部件(或更高级别的小部件)的重新渲染,因此键盘立即关闭。

如果我要全部添加,那么这个问题有很多代码副本-因此,我将首先尝试添加关键部分。希望这足以解释发生了什么。

首先我们有了Tab:这是传递给TabController的模型

typedef OnBuild = Widget Function(BuildContext context);

class Tab {
  final IconData icon;
  final String label;
  final Color highlightedColor;

  final OnBuild buildBody;

  final Widget body;

  Tab({
    this.buildBody,
    this.icon,
    this.label,
    this.highlightedColor,
    this.highlighted = false,
    this.selected = false,
    this.body,
  });

  bool highlighted;

  bool selected;
}

这里有TabController,将其作为StatefulWidget读取。尽管我创建了BaseController和BaseView试图将逻辑与渲染分离,但是从理论上讲,它是一个StatefulWidget。

class TabPageController extends BaseController {
  final TabSelected tabSelected;
  final List<Tab> tabs;
  final Map<Tab, GlobalKey> _tabs = {};

  Tab selectedTab;

  TabPageController({@required this.tabs, this.tabSelected}) {
    tabs.forEach((t) {
      _tabs.putIfAbsent(t, () => GlobalKey());
    });

    /// Always select the first tab
    selectedTab = tabs[0];

    selectedTab.selected = true;
  }

  void selectTab(Tab tab) {
    bool _refreshNeeded = false;

    tabs.forEach((t) {
      if (t == tab) {
        if (!(tab.selected ?? true)) {
          _refreshNeeded = true;

          /// Set selected as true
          /// on the one that is seleted
          /// unless its already selected
          t.selected = true;

          selectedTab = t;

          /// Let consumer know of the tab change
          if (tabSelected != null) {
            tabSelected(tabs.indexOf(t), t);
          }
        }
      } else if (t.selected ?? false) {
        /// Set selected as false on
        /// the other one(s, theoretically)
        /// that are selected
        t.selected = false;
      }
    });

    if (_refreshNeeded) {
      refresh();
    }
  }

  bool needPaint = false;

  /// Highlight the tab 
  /// from other widget(s)
  void highlightTab(Tab tab, bool highlight) {
    if (tab.highlighted != highlight) {
      tab.highlighted = highlight;

      /// Re-draw the tab
      _tabs[tab].currentState.setState(() {});
    }
  }
}

class TabPage extends BaseView {
  final TabPageController controller;

  TabPage({this.controller});

  @override
  Widget build(BuildContext context) {
    if (!mounted) {
      return Container();
    }

    print('BUILDING: ' + DateTime.now().toIso8601String());

    if (controller._tabs == null || controller._tabs.length == 0) {
      return Container();
    }

    if(controller.tabs.length == 1){
      return controller.selectedTab.buildBody(context);
    }

    List<Widget> children = <Widget>[];

    controller._tabs.forEach((tab, key) {
      children.add(Expanded(
        child:
            _TabWidget(tab: tab, tabSelected: controller.selectTab, key: key),
      ));
    });

    return Column(
      children: <Widget>[
        /// Tab selector
        Container(
          height: getMinimizedListItemHeight(context),
          child: Row(
            children: children,
          ),
        ),

        /// The tab body
        Expanded(
          child: controller.selectedTab.buildBody(context),
          key: GlobalKey(),
        ),
      ],
    );
  }
}

class _TabWidget extends StatefulWidget {
  final Tab tab;

  final _InternalTabSelected tabSelected;

  _TabWidget(
      {@required this.tab, @required this.tabSelected, @required Key key})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _TabWidgetState();
}

class _TabWidgetState extends State<_TabWidget> {
  @override
  Widget build(BuildContext context) {
    Color color;

    if (widget.tab.highlighted) {
      color = widget.tab.highlightedColor;

      if (!(widget.tab.selected ?? true)) {
        color = color.withOpacity(0.5);
      }
    } else {
      if (widget.tab.selected ?? false) {
        color = ServiceProvider
            .instance.instanceStyleService.appStyle.activeIconColor;
      } else {
        color = ServiceProvider
            .instance.instanceStyleService.appStyle.inactiveIconColor;
      }
    }

    return Column(
      children: <Widget>[
        Expanded(
          child: Container(
            child: IconButton(
              onPressed: () {
                widget.tabSelected(widget.tab);
              },
              icon: Icon(
                widget.tab.icon,
                size: getAppBarIconSize(context),
                color: color,
              ),
            ),
          ),
        ),
        Container(
          height: getDefaultPadding(context),
          color: color,
        ),
      ],
    );
  }
}

如果仅将一个Tab传递给控制器​​并且触发此条件,则它将按预期工作(因为此选项仅将Tab主体呈现为主体,而不是呈现标头部分)。这就是为什么我知道Tab实现会产生此错误的原因。

if(controller.tabs.length == 1){
   return controller.selectedTab.buildBody(context);
}

我希望有人可以看到这里出了什么问题,否则我可能只需要在制表符更改上返回一个索引,然后让消费者根据该索引决定要呈现的内容,例如BottomNavigationBar可以执行的操作。但是,我希望将标签页与其主体部件紧密结合。

渲染中的以下代码是在以下事件上触发的:

print('BUILDING: ' + DateTime.now().toIso8601String());
  1. 页面加载
  2. TextField是重点
  3. 键盘打开
  4. 键盘关闭

0 个答案:

没有答案