How do I give a TextField full width inside a coul

2019-07-15 14:46发布

问题:

I have this layout:

OverlayEntry _createOverlayEntry() {
    RenderBox renderBox = context.findRenderObject();
    var size = renderBox.size;
    var offset = renderBox.localToGlobal(Offset.zero);

    return OverlayEntry(
        builder: (context) => Positioned(
          left: offset.dx,
          top: offset.dy + 38.0,
          width: size.width,
          child: Material(
            elevation: 6.0,
            child: Padding(
              padding: EdgeInsets.all(8.0),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.only(right: 8.0),
                    child: Icon(Icons.check_box_outline_blank),
                  ),
                  Column(
                    children: <Widget>[
                      Container(
                        height: 30.0,
                        width: 100.0,
                        color: Colors.green,
                        child: TextField(
                          decoration: InputDecoration(
                              border: InputBorder.none,
                              hintText: "New To-Do"
                          ),
                        ),
                      ),
                      Container(
                        height: 30.0,
                        width: 100.0,
                        color: Colors.blue,
                        child: TextField(
                          decoration: InputDecoration(
                              border: InputBorder.none,
                              hintText: "Notes"
                          ),
                        ),
                      )
                    ],
                  )
                ],
              ),
            )
          ),
        )
    );
  }

Which gives me this ui:

Now I would like to not set a hardcoded width and height for the TextField's and have them take just the height they need and all the remaning width the column offers. I tried with the following layout but it crashes with the message "RenderFlex children have non-zero flex but incoming height constraints are unbounded", so could you help explain how I can do this in Flutter please?

回答1:

There's a few things that are interesting about the approach you've taken here. Also, I'm going on the basis that you're trying to make the overlay be shown at the same place at the top of the screen each time, rather than over whatever you've tapped on, since that's shown in the video you posted on another question.

The first interesting thing is that you've obtained a renderbox from the place where the _createOverlayEntry function is being called:

RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
var offset = renderBox.localToGlobal(Offset.zero);

This means that you're actually using the offset of the renderbox of whatever is calling this function - which is likely not what you're trying to do. It's probably working just fine if you're putting this in the build of a widget that displays the entire screen, but it's something to consider and likely change.

The second thing you're doing is

top: offset.dy + 38.0,

which probably has a reason, but I'm generally a bit wary when I see arbitrary sizes in code for no particular reason. If you're trying to avoid the top bar, I'd recommend kToolbarHeight + ??, and if you're trying to avoid the status bar etc at the top of the screen you should use SafeArea.

And lastly, you probably don't need to be using positioned at all. If you use an alignment instead you can do this:

OverlayEntry(
  builder: (context) {
    return SafeArea(
      child: Padding(
        padding: EdgeInsets.only(top: 38, left: 10, right: 10),
        child: Align(
          child: Material(
            elevation: 6.0,
            child: Padding(
              padding: EdgeInsets.all(8.0),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.only(right: 8.0),
                    child: Icon(Icons.check_box_outline_blank),
                  ),
                  Expanded(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Container(
                          color: Colors.green,
                          child: TextField(
                            decoration: InputDecoration(
                                border: InputBorder.none,
                                hintText: "New To-Do"),
                          ),
                        ),
                        Container(
                          color: Colors.blue,
                          child: TextField(
                            decoration: InputDecoration(
                                border: InputBorder.none, hintText: "Notes"),
                          ),
                        )
                      ],
                    ),
                  )
                ],
              ),
            ),
          ),
          alignment: Alignment.topCenter,
        ),
      ),
    );
  },
);

The two important parts of that are the column's mainAxisSize - if you don't set that it expands to take the entire screen; and the Expanded that is wrapping the column which makes sure that child of the row takes up all available space.

Also, you should remove the width from your container objects. I removed the height as well, but that is up to you.



回答2:

Don't specify height and width of the containers (the column's children) and try:

Width

Setting crossAxisAlignment: CrossAxisAlignment.stretch, for your column. Perhaps that might work for letting the width of the column stretch to that of the row it is in.

To set the width of the row, you can wrap your row in a container and use width: MediaQuery.of(context).size.width,. This gets the screen size width.

Height

You can wrap each of the columns children in Expanded and specify the flex they should have in the column's height.

To set the height of the column, you can wrap your row in a container and use height: MediaQuery.of(context).size.height,. This gets the screen size height. You may want to divide it with a value say 10 so width: MediaQuery.of(context).size.height/10,

There is a useful cheat sheet here: Cheat Sheet