skip to Main Content

Okay, so this is a bit of a difficult one to explain.

I would like two TextFields right above/below each other. The problem comes when you type in to one of the TextFields and the result should be shown in a variable-sized container above other content WITHOUT pushing other content down.

I could just use a Stack with Positioned, BUT then I get problems with exact positioning because of different screen-sizes, fonts and text-sizes on devices. If I use a Column, the content gets pushed down.

See the screenshots to help understand my problem (code further below)

This is what it should look like for all screens / sizes / fonts / etc.
I can get this result with Stack+Positioned, but I get the problem illustrated further down. (the red box is the variable sized result container).

Screenshot of two TextFields

Overlapping container as expected on top widget

Overlapping container as expected on bottom widget

This is what happens when I use Stack+Positioned and the text-size is increased on the phone (or font is different, or something else like that).

Screenshot of two TextFields overlapping

This is what happens when I put the TextFields in a columnn.

Container pushing other widget down

Code

This is obviously just example code. In the real app, we have two address searches that calls an API to the the result list.

class StackProblemExample extends StatelessWidget {    

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          top: 82,
          left: 0,
          right: 0,
          child: TextFieldAndResultList(
            hint: 'To',
            isTop: false,
          ),
        ),
        Positioned(
          top: 20,
          left: 0,
          right: 0,
          child: TextFieldAndResultList(
            hint: 'From',
            isTop: true,
          ),
        ),
      ],
    );
  }
}

class TextFieldAndResultList extends StatefulWidget {
  final String hint;
  final bool isTop;

  const TextFieldAndResultList({
    super.key,
    required this.hint,
    required this.isTop,
  });

  @override
  State<TextFieldAndResultList> createState() => _TextFieldAndResultListState();
}

class _TextFieldAndResultListState extends State<TextFieldAndResultList> {
  var controller = TextEditingController();
  var containerHeight = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          decoration: InputDecoration(
            hintText: widget.hint,
            border: OutlineInputBorder(
              borderRadius: widget.isTop
                  ? BorderRadius.only(
                      topLeft: Radius.circular(10),
                      topRight: Radius.circular(10),
                    )
                  : BorderRadius.only(
                      bottomLeft: Radius.circular(10),
                      bottomRight: Radius.circular(10),
                    ),
            ),
          ),
          controller: controller,
          onChanged: (value) {
            setState(() {
              containerHeight = controller.text.length * 10;
            });
          },
        ),
        if (containerHeight > 0)
          Container(
            height: containerHeight.toDouble(),
            color: Colors.red,
          ),
      ],
    );
  }
}

How in the world could I achieve that the tow TextFields (with each their own result container) can be stacked after each other without concrete positions AND not push each other down?

2

Answers


  1. Chosen as BEST ANSWER

    The Flutter widget Autocomplete, suggested by @user18309290, did not provide good enough flexibility for me, so I solved this problem by using CustomMultiChildLayout to calculate where the widgets should be positioned in relation to each other.

    Please see this great explanation on how to use CustomMultiChildLayout if you want more control over you widgets than Autocomplete provides.


  2. Use Autocomplete instead, it is designed to do exactly this.

    A widget for helping the user make a selection by entering some text and choosing from among a list of options.

    Autocomplete<String>(
      fieldViewBuilder: (BuildContext context,
          TextEditingController fieldTextEditingController,
          FocusNode fieldFocusNode,
          VoidCallback onFieldSubmitted) {
        return TextFormField(
          decoration: InputDecoration(
    ...
          ),
          controller: fieldTextEditingController,
          focusNode: fieldFocusNode,
        );
      },
      optionsBuilder: (textEditingValue) {
        ...
      },
      optionsViewBuilder: (context, onSelected, options) {
        ...
      },
      onSelected: (selection) {
        ...
      },
    );
    

    To style the box of the autocomplete options: see this question

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search