ReorderableListView: Exception: BoxConstraints forces an infinite height
Asked Answered
B

5

7

TL;DR - How to achieve shrinkWrap = true in a ReorderableListView?

I was trying to create a ReoderableListView with Column<-Container as parent, this error occured.

I/flutter (32618): The following assertion was thrown during performLayout():
I/flutter (32618): BoxConstraints forces an infinite height.


I/flutter (32618): The following RenderObject was being processed when the exception was fired: RenderStack#23840 relayoutBoundary=up17 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE:
I/flutter (32618):   creator: Stack ← _Theatre ← Overlay-[GlobalKey#dc153 ReorderableListView overlay key] ←
I/flutter (32618):     ReorderableListView ← StreamBuilder<QuerySnapshot> ← Column ← Padding ← Padding ← Container ←
I/flutter (32618):     BoardCard ← Column ← _SingleChildViewport ← ⋯
I/flutter (32618):   parentData: not positioned; offset=Offset(0.0, 0.0) (can use size)
I/flutter (32618):   constraints: BoxConstraints(0.0<=w<=328.0, 0.0<=h<=Infinity)
I/flutter (32618):   size: MISSING
I/flutter (32618):   alignment: AlignmentDirectional.topStart
I/flutter (32618):   textDirection: ltr
I/flutter (32618):   fit: expand
I/flutter (32618):   overflow: clip
I/flutter (32618): This This RenderObject had the following child:
I/flutter (32618):     child 1: _RenderLayoutBuilder#55d3d NEEDS-LAYOUT NEEDS-PAINT

This would have been fixed very easily if it was ListView by using shrinkWrap = true but ReorderableListView does not have the this property.

Here is the code

@override
  Widget build(BuildContext context) {
    final _listTitleStyle =
        TextStyle(fontSize: 20, fontWeight: FontWeight.w500);
    final _listSubTitleStyle = TextStyle(
      fontSize: 14,
      fontWeight: FontWeight.w400,
      color: Color(0xff7D7373),
    );
    return Container(
      padding: EdgeInsets.all(8),
      margin: EdgeInsets.all(8),
      child: Column(
        children: <Widget>[
          Container(
            child: Row(
              children: <Widget>[
                Expanded(
                  child: Row(
                    textBaseline: TextBaseline.alphabetic,
                    crossAxisAlignment: CrossAxisAlignment.baseline,
                    children: <Widget>[
                      Text(
                        widget.cardTitle,
                        style: _listTitleStyle,
                      ),
                      SizedBox(
                        width: 2,
                      ),
                      Text(
                        widget.cardSubTitle,
                        style: _listSubTitleStyle,
                      ),
                    ],
                  ),
                ),
                Icon(Icons.keyboard_arrow_down),
              ],
            ),
          ),
          SizedBox(
            height: 8,
          ),
          StreamBuilder<QuerySnapshot>(
              stream: widget.query,
              builder: (context, snapshot) {
                if (!snapshot.hasData) return LinearProgressIndicator();
                return _buildList(context, snapshot.data.documents);
              }),
        ],
      ),
    );
  }

  Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
    snapshot.forEach((snap) {
      print("debug 1 ${snap.data}");
      print(TodoItem.fromSnapshot(snap, snap.reference).toString());
    });
    return ReorderableListView(
      onReorder: (oldIndex, newIndex){},
      children: snapshot
          .map((data) => TodoTile(TodoItem.fromSnapshot(data, data.reference), key: UniqueKey(),))
          .toList(),
    );
  }
Beaston answered 22/6, 2019 at 8:52 Comment(3)
Wrap ReorderableListView inside a container and give it a heightRosenwald
@Abdulrahman Doing that is not an option because i want the height to be sum of heights of the children, Similar to WrapContentBeaston
It's probably because it's inside a Column -- see #52801701Nancinancie
B
-1

I have fixed this problem by replacing ReorderableListView by the package flutter_reorderable_list, it accepts a child (Widget) unlike ReorderableListView which accepts children (List)

Its implementation is a bit more complex. You can look at the example to get some understanding of implementing it correctly.

Beaston answered 30/6, 2019 at 9:4 Comment(1)
If you have a simplified example, it would be great if you posted it here :)Unhealthy
S
0

You're missing an Expanded around your StreamBuilder.

blow is an example that can be executed on https://dartpad.dev with the same structure you provided.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Reorderable ListView Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ReorderableListViewExample(),
    );
  }
}

class ReorderableListViewExample extends StatefulWidget {
  @override
  _ReorderableListViewExampleState createState() =>
      _ReorderableListViewExampleState();
}

class _ReorderableListViewExampleState
    extends State<ReorderableListViewExample> {
  List<String> items = List.generate(100, (index) => "Item $index");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Reorderable ListView Example'),
      ),
      body: Container(
        padding: EdgeInsets.all(8),
        margin: EdgeInsets.all(8),
        child: Column(
          children: [
            Row(
              children: <Widget>[
                Expanded(
                  child: Row(
                    textBaseline: TextBaseline.alphabetic,
                    crossAxisAlignment: CrossAxisAlignment.baseline,
                    children: <Widget>[
                      Text('Demo '),
                      SizedBox(width: 2),
                      Text('Demo '),
                    ],
                  ),
                ),
                Icon(Icons.keyboard_arrow_down),
              ],
            ),
            SizedBox(height: 8),
            Expanded(
              child: ReorderableListView(
                onReorder: (oldIndex, newIndex) {
                  setState(() {
                    if (oldIndex < newIndex) {
                      newIndex -= 1;
                    }
                    final String item = items.removeAt(oldIndex);
                    items.insert(newIndex, item);
                  });
                },
                children: <Widget>[
                  for (final item in items)
                    ListTile(
                      key: ValueKey(item),
                      title: Text(item),
                    ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

enter image description here

Stolzer answered 10/4 at 18:3 Comment(0)
B
-1

I have fixed this problem by replacing ReorderableListView by the package flutter_reorderable_list, it accepts a child (Widget) unlike ReorderableListView which accepts children (List)

Its implementation is a bit more complex. You can look at the example to get some understanding of implementing it correctly.

Beaston answered 30/6, 2019 at 9:4 Comment(1)
If you have a simplified example, it would be great if you posted it here :)Unhealthy
Q
-1

I agree with Abdulrahman Falyoun. you just have to make the height dynamic and adjust it based on the number of items in the list.

 Container(
      height: (list.length * 40).toDouble(),
      padding: const EdgeInsets.all(10),
      child: ReorderableListView(
        children: list.map((item) {
          return getItem(item);
        }).toList(),
        onReorder: _onReorder,
      ),
    )

or if it's within a column, then have it wrap with Expanded()

Quadrangular answered 5/6, 2020 at 8:10 Comment(1)
This works, but with a limitation: the height of the list items must be fixed. For instance, consider the possibility that items contain text of variable length, that could possibly wrap; in that case, it won't be possible to calculate the total height based of the number of items.Reportorial
R
-1

I have found a solution by using the reorderables package. Your find it here: https://pub.dev/packages/reorderables

More specifically, I have used the ReorderableColumn class, that works much like a Column class, but also has an onReorder callback. So it is very straightforward.

By default, it expects a long tap to start dragging, which might be good on a mobile device, but since I am developing for the desktop I have set option needsLongPressDraggable to false.

Reportorial answered 10/4 at 17:12 Comment(0)
W
-4

use Columnto listview and apply shrinkWrap = true

@override
  Widget build(BuildContext context) {
    final _listTitleStyle =
        TextStyle(fontSize: 20, fontWeight: FontWeight.w500);
    final _listSubTitleStyle = TextStyle(
      fontSize: 14,
      fontWeight: FontWeight.w400,
      color: Color(0xff7D7373),
    );
    return Container(
      padding: EdgeInsets.all(8),
      margin: EdgeInsets.all(8),
      child: Listview(
        shrinkWrap = true
        children: <Widget>[
          Container(
            child: Row(
              children: <Widget>[
                Expanded(
                  child: Row(
                    textBaseline: TextBaseline.alphabetic,
                    crossAxisAlignment: CrossAxisAlignment.baseline,
                    children: <Widget>[
                      Text(
                        widget.cardTitle,
                        style: _listTitleStyle,
                      ),
                      SizedBox(
                        width: 2,
                      ),
                      Text(
                        widget.cardSubTitle,
                        style: _listSubTitleStyle,
                      ),
                    ],
                  ),
                ),
                Icon(Icons.keyboard_arrow_down),
              ],
            ),
          ),
          SizedBox(
            height: 8,
          ),
          StreamBuilder<QuerySnapshot>(
              stream: widget.query,
              builder: (context, snapshot) {
                if (!snapshot.hasData) return LinearProgressIndicator();
                return _buildList(context, snapshot.data.documents);
              }),
        ],
      ),
    );
  }

  Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
    snapshot.forEach((snap) {
      print("debug 1 ${snap.data}");
      print(TodoItem.fromSnapshot(snap, snap.reference).toString());
    });
    return ReorderableListView(
      onReorder: (oldIndex, newIndex){},
      children: snapshot
          .map((data) => TodoTile(TodoItem.fromSnapshot(data, data.reference), key: UniqueKey(),))
          .toList(),
    );
  }
Wadleigh answered 22/6, 2019 at 10:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.