Home > Net >  Horizontal scrolling ListView.builder inside SingleChildScrollView - wrap content height
Horizontal scrolling ListView.builder inside SingleChildScrollView - wrap content height

Time:09-17

My layout is a Form widget with some controls:

Column(
      mainAxisAlignment: MainAxisAlignment.start,
      mainAxisSize: MainAxisSize.max,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Form(
          key: widget.addEventFormKey,
          onChanged: () {},
          child: Expanded(
            child: SingleChildScrollView(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Text(CustomResources.strings["add_event_category_label"], style: TextStyle(fontWeight: FontWeight.bold)),
                  
                  /*some other widgets*/
                  
                  Visibility(
                    child: Container(
                      height: 200.0,
                      child: ListView.builder(
                        scrollDirection: Axis.horizontal,
                        itemCount: _attachments?.length,
                        itemBuilder: (context, index) {
                          return Stack(
                            children: [
                              Container(
                                margin: EdgeInsets.fromLTRB(0, 0, 5, 0),
                                child: Stack(
                                  children: [
                                    ClipRRect(
                                      child: Image.file(File(_attachments[index]), cacheWidth: 200),
                                      borderRadius: BorderRadius.circular(8.0),
                                    ),
                                  ],
                                ),
                              ),
                              IconButton(
                                onPressed: () {
                                  File(_attachments[index]).delete();
                                  setState(() => _attachments.remove(_attachments[index]));
                                },
                                icon: Icon(FontAwesomeIcons.trash, color: Colors.white, size: 20),
                                padding: EdgeInsets.only(top: 4, left: 4),
                                constraints: BoxConstraints(),
                              ),
                            ],
                          );
                        },
                      ),
                    ),
                    visible: _attachments.length > 0,
                  ),
                  Visibility(child: Padding(padding: EdgeInsets.fromLTRB(0, 18, 0, 0)),visible: _attachments.length > 0),
                  SizedBox(
                    child: RaisedButton(
                        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24.0)),
                        onPressed: _attachments.length < 3 ? () => _pickImage() : null,
                        padding: EdgeInsets.all(12.0),
                        color: Colors.blue,
                        child: Text(CustomResources.strings["add_event_add_photo_button_label"], style: TextStyle(color: Colors.white))),
                    width: double.infinity,
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );

Problematic part is ListView.builder to display horizontally scrolled list of images. As you can see, picture will always get fixed width (200) and unknown height, because height depends from image aspect ratio. ListView.builder is wrapped with Container, so now it has constant height 200.

I want to force my ListView.builder to expand to child image height (it's single row ListView scrolled horizontally), image width always 200 and other widgets should be placed below it without any remaining space. With current approach, if image height is < 200, there will be remaining space left below image list. If image height is >200, image will be scaled (width/height).

I tried to wrap list view with Expanded widget instead Container, but it throws exception:

RenderFlex children have non-zero flex but incoming height constraints are unbounded.

It says I still need to provide height, which I don't want to. How to solve this?

CodePudding user response:

If you got RenderFlex children have non-zero flex but incoming height constraints are unbounded. try below code hope its help to you. add your Column inside Expanded() Widget and remove SingleChildScrollView() in your code

Expanded(
  child: Column(
     children:[
     //Your Widgets
      ],
   ),
),

CodePudding user response:

I think that's not possible with ListView.builder, because its height with dynamic items is not known while building widgets tree. Instead, my thumbnail widgets mus be built upfront, and added to Row after they have been built and wrap row with SingleChildScrollView to make it scrollable. So, my thumbnails list ready to place to my Form:

class AttachmentsListWidget extends StatelessWidget {
  const AttachmentsListWidget({
    Key key,
    @required this.items,
    @required this.onAttachmentDeleted,
  }) : super(key: key);

  final List<String> items;
  final Function(String) onAttachmentDeleted;

  @override
  Widget build(BuildContext context) {
    var _thumbnailsScrollController = ScrollController();
    final thumbnails = <Widget>[];
    Widget thumbnailsWidget;

    if (items.length > 0) {
      for (int i = 0; i < items.length; i  ) {
        thumbnails.add(
          AttachmentWidget(
            attachment: items[i],
            onDeleteClicked: (String attachment) => onAttachmentDeleted(attachment),
          ),
        );
      }
      thumbnailsWidget = Container(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Scrollbar(
              isAlwaysShown: true,
              controller: _thumbnailsScrollController,
              child: SingleChildScrollView(
                controller: _thumbnailsScrollController,
                scrollDirection: Axis.horizontal,
                child: Row(
                  children: thumbnails,
                  crossAxisAlignment: CrossAxisAlignment.start,
                ),
              ),
            ),
          ],
        ),
      );
    } else {
      thumbnailsWidget = Container();
    }
    return thumbnailsWidget;
  }
}

(also, always visible scrollbar added).

  • Related