首页 > 解决方案 > Flutter:使用带有 BottomNavigationBar 的可扩展文本字段

问题描述

我需要一些关于这个布局的帮助:)

布局包含一个BottomNavigationBar. 正文由Container顶部的 a(用作某种标题)TextfieldContainer. 应该扩展以Textfield填充剩余空间。一旦用户输入了足够多的行以使文本不适合屏幕,整个正文 (TextfieldContainer) 应该变成scrollable.

所以它基本上是一个笔记应用程序,带有一个HeaderContainer部分)和多个Tabs用于记笔记。

在此处输入图像描述

这是迄今为止的解决方案:

  Scaffold buildBody(BuildContext context) {
    return Scaffold(
      appBar: AppBar(...),
      body: _buildScaffoldBody(),
      bottomNavigationBar: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          AnimatedCrossFade(
            firstChild: Material(
              color: Theme.of(context).primaryColor,
              child: TabBar(
                controller: _tabController,
                tabs: _tabNames,
                onTap: (int) {
                 ...
                },
              ),
            ),
            secondChild: Container(),
            crossFadeState: _screen == 0
                            ? CrossFadeState.showFirst
                            : CrossFadeState.showSecond,
            duration: const Duration(milliseconds: 300),
          ),
        ],
      ),
    );
  }

Widget _buildScaffoldBody() {
return LayoutBuilder(
      builder: (context, constraint) {
        return SingleChildScrollView(
          child: ConstrainedBox(
            constraints: BoxConstraints(minHeight: constraint.maxHeight),
            child: IntrinsicHeight(
              child: Column(
                children: <Widget>[
                  Container(
                    height: 100,
                    alignment: Alignment.center,
                    color: Colors.green,
                    child: Text("Header"),
                  ),
                 Expanded(              //This is probably the cause 
                    child:  TabBarView(    //of the exception
                        controller: _tabController,
                        children: <Widget>[
                          TextField(
                            expands: true,
                            maxLines: null,
                            decoration: InputDecoration(
                                fillColor: Colors.blue[200], filled: true),
                          ),
                          TextField(
                            expands: true,
                            maxLines: null,
                            decoration: InputDecoration(
                                fillColor: Colors.blue[200], filled: true),
                          ),
                          TextField(
                            expands: true,
                            maxLines: null,
                            decoration: InputDecoration(
                                fillColor: Colors.blue[200], filled: true),
                          ),
                        ]
                      )
                    )
                ],
              ),
            ),
          ),
        );
      },
    );

但它抛出了一个异常。我尝试用aExpandedContainer硬编码替换. 如果我这样做,则不会引发异常,但不再是并且它不会与. 它只在包装内滚动。heightwidthTextfieldexpandableHeaderContainerTextfield

The following assertion was thrown during performLayout():
I/flutter ( 8080): RenderViewport does not support returning intrinsic dimensions.
I/flutter ( 8080): Calculating the intrinsic dimensions would require instantiating every child of the viewport, which
I/flutter ( 8080): defeats the point of viewports being lazy.
I/flutter ( 8080): If you are merely trying to shrink-wrap the viewport in the main axis direction, consider a
I/flutter ( 8080): RenderShrinkWrappingViewport render object (ShrinkWrappingViewport widget), which achieves that
I/flutter ( 8080): effect without implementing the intrinsic dimension API.
I/flutter ( 8080): 
I/flutter ( 8080): The relevant error-causing widget was:
I/flutter ( 8080):   IntrinsicHeight

标签: androidflutterflutter-layout

解决方案


你只是有些东西放错了地方。尽可能多地尝试将代码分解为可重用的小部件。它有助于使一切更有条理。

此外,作为一般规则,当您尝试实现通常需要的东西时,很可能已经为它构建了一个小部件。在这种情况下,您不需要弄乱AnimatedCrossFade等...它都内置在TabBarView.

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TabBarScaffold(),
    );
  }
}

class TabBarScaffold extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      color: Colors.yellow,
      home: DefaultTabController(
        length: 3,
        child: new Scaffold(
          body: MyPages(),
          bottomNavigationBar: MyTabs(),
        ),
      ),
    );
  }
}

class MyTabs extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return TabBar(
      tabs: [
        Tab(
          child: Text("Tab 1"),
        ),
        Tab(
          child: Text("Tab 2"),
        ),
        Tab(
          child: Text("Tab 3"),
        ),
      ],
      labelColor: Colors.blue,
      unselectedLabelColor: Colors.black,
      indicatorSize: TabBarIndicatorSize.label,
      indicatorPadding: EdgeInsets.all(5.0),
      indicatorColor: Colors.red,
    );
  }
}

class MyPages extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return TabBarView(
      children: [
        MyPageBody(
          textBackgroundColor: Colors.blue[200],
        ),
        MyPageBody(
          textBackgroundColor: Colors.green[200],
        ),
        MyPageBody(
          textBackgroundColor: Colors.red[200],
        ),
      ],
    );
  }
}

class MyPageBody extends StatelessWidget {
  final Color textBackgroundColor;
  MyPageBody({this.textBackgroundColor});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraint) {
        return SingleChildScrollView(
          child: ConstrainedBox(
            constraints: BoxConstraints(minHeight: constraint.maxHeight),
            child: IntrinsicHeight(
              child: Column(
                children: <Widget>[
                  Container(
                    height: 100,
                    alignment: Alignment.center,
                    color: Colors.green,
                    child: Text("Header"),
                  ),
                  Expanded(
                    child: TextField(
                      expands: true,
                      maxLines: null,
                      decoration: InputDecoration(
                          fillColor: textBackgroundColor, filled: true),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}

推荐阅读