Skip to content

Wrap widget doesn't layout correctly in certain cases, like Column does #61204

@dannyvalentesonos

Description

@dannyvalentesonos

When using the technique listed here, under the heading "Expanding content to fit the viewport": https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html,

a Column widget works very well, but a Wrap does not. Is there something maybe missing from the way the Wrap widget lays itself out that could be improved to act more like a Column?

Essentially, the following sample shows the problem. If you run this app on a device, it should start out with a view that can be scrolled so all children are accessible. Hitting the button at the top to switch to using a Wrap will cause an Overflow.
Switching back to a Column, you can scroll again, and if you change the number in the text field to a smaller number, you can get the Wrap widget to work well as long as no Overflow happens.

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: WrapHomePage(),
    );
  }
}

class WrapHomePage extends StatefulWidget {
  const WrapHomePage();

  @override
  _WrapHomePageState createState()  => _WrapHomePageState();
}

class _WrapHomePageState extends State<WrapHomePage> {

  bool _useColumn = true;
  int _numTexts = 8;

  List<Widget> _buildTexts(int numTexts) {
    List<Widget> texts = [];
    for (int i=0; i<numTexts; i++) {
      texts.add(Padding(
        padding: const EdgeInsets.only(top: 24.0),
        child: Text(
            "Hello, this is some long text. It can go on and on. This test is to make sure we can scroll"),
      ));
    }
    return texts;
  }

  @override
  Widget build(BuildContext context) {

    final texts = _buildTexts(_numTexts);

    return Scaffold(
        body: SafeArea(
          child: Padding(
            padding: const EdgeInsets.all(24),
            child: LayoutBuilder(
              builder: (context, constraints) {
                return SingleChildScrollView(
                    child: ConstrainedBox(
                      constraints: BoxConstraints(
                        minHeight: constraints.maxHeight,
                      ),
                      child: IntrinsicHeight(
                        child: DefaultTextStyle(
                          style: TextStyle(fontSize: 20, color: Colors.black),
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            mainAxisSize: MainAxisSize.max,
                            children: [
                              FlatButton(
                                  onPressed: () {
                                    setState(() {
                                      _useColumn = !_useColumn;
                                    });
                                  },
                                  child: Text(_useColumn ? "Switch to Wrap!" : "Switch to Column!", style: TextStyle(fontSize: 20, color: Colors.black))
                              ),
                              if (_useColumn)
                                Column(
                                  key: ValueKey("header"),
                                  children: texts,
                                )
                              else
                                Wrap(
                                  key: ValueKey("header"),
                                  children: texts,
                                ),
                              Expanded(
                                  key: ValueKey("middle"),
                                  child: Container(
                                    color: Colors.red,
                                    child: Center(
                                        child: TextField(
                                          onChanged: (value) {
                                            setState(() {
                                              _numTexts = int.parse(value);
                                            });
                                          },
                                        )
                                    ),
                                  )
                              ),
                              Padding(
                                key: ValueKey("footer"),
                                padding: const EdgeInsets.only(top: 24.0),
                                child: Column(
                                  children: [
                                    Text("Final message")
                                  ],
                                ),
                              )
                            ],
                          ),
                        ),
                      ),
                    )
                );
              }
            ),
          )
        )
    );
  }
}

Metadata

Metadata

Assignees

Labels

P0Critical issues such as a build break or regressionf: scrollingViewports, list views, slivers, etc.found in release: 1.20Found to occur in 1.20frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work on

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions