Flutter: Using Expandable Textfield with BottomNavigationBar

牧云@^-^@ 提交于 2020-03-25 19:14:33

问题


I need some help with this layout :)

The Layout contains a BottomNavigationBar. The body consists of a Container at the top (which serves as some kind of header) and a Textfield below the Container. The Textfield should expand to fill the remaining space. As soon as the user enters enough lines so that the text doesn't fit on the screen, the whole body (Textfield and Container) should become scrollable.

So it's basically a note app with a Header (the Container part) and multiple Tabs for Note taking.

This is the solution so far:

  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),
                          ),
                        ]
                      )
                    )
                ],
              ),
            ),
          ),
        );
      },
    );

But it's throwing an exception.I tried replacing Expanded with a Container and hardcoding height and width. If I do so the exception is not thrown, but the Textfield is no longer expandable and it doesn't scroll together with the Header. It only scrolls within the Container wrapping the Textfield.

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

回答1:


You just have some stuff misplaced. Try as much as you can to break apart your code into re-usable widgets. It helps to keep everything more organized.

Also, as a general rule, when you're trying to implement something commonly needed, chances are there will be a widget built for it already. In this case, you don't need to mess with the AnimatedCrossFade etc... It's all built into the 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),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}


来源:https://stackoverflow.com/questions/59993861/flutter-using-expandable-textfield-with-bottomnavigationbar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!