flutterlistviewclippingvertical-scrolling

How do I stop contents of my ListView extending beyond its boundaries when scrolling in Flutter?


I have a strange problem with a ListView in my Flutter app.

I have a ListView sitting within a SizedBox of 220 pixels height. When the list items exceed the available height, then they bleed over into surrounding screen elements.

Weirdly there is ONE property of the ListTile's that DO clip and that's the title! but everything else, the color and shape etc... bleeds into the rest of the screen so I get a load of blue boxes extending beyond my container.

Can anyone advise how I can have the ENTIRE ListTile clip when it meets the edge of its container?

Please reference the screenshot to see what I mean and i'll paste my code below the image

List Tiles extending beyond listView boundaries

Here's my build method...

    @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          elevation: 0,
          backgroundColor: Colors.transparent,
          leading: const CloseButton(),
          actions: [
            ElevatedButton.icon(
              label: const Text('SAVE'),
              icon: const Icon(Icons.done),
              onPressed: () async {
                Navigator.pop(context);
                widget.resolution?.wasSaved = true;
                setState(() {
                  resolution.title = titleController.text;
                });
                widget.onSaved(resolution);
              },
              style: ElevatedButton.styleFrom(
                primary: Colors.transparent,
                elevation: 0,
              ),
            ),
          ],
        ),
        body: Container(
          // height: size.height,
          padding: const EdgeInsets.all(12),
          child: Column(
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text('RESOLUTION', style: kInputFieldHeader),
                  const SizedBox(height: 4),
                  Card(
                    elevation: 2,
                    child: TextFormField(
                      style: kInputFieldText,
                      controller: titleController,
                      decoration: InputDecoration(
                          border: OutlineInputBorder(),
                          suffixIcon: titleController.text.isEmpty
                              ? Container(
                                  width: 0,
                                )
                              : IconButton(
                                  onPressed: () => titleController.clear(),
                                  icon: Icon(Icons.close))),
                      onFieldSubmitted: (fieldText) {
                        setState(() {
                          resolution.title = fieldText;
                        });
                        ;
                      },
                      validator: (value) => value != null && value.isEmpty
                          ? 'Please enter something'
                          : null,
                    ),
                  ),
                  DatePickers(
                    resolution: resolution,
                    startDateCallback: (startDate) {
                      setState(() {
                        resolution.startDate = startDate;
                      });
                    },
                    endDateCallback: (endDate) {
                      setState(() {
                        resolution.endDate = endDate;
                      });
                    },
                  ),
                  CustomColorPicker(
                    resolution: resolution,
                    colorCallback: (color) =>
                        setState(() => resolution.color = color),
                  ),
                  CustomProgressIndicator(
                      resolution: resolution, isCommitment: false),
                ],
              ),
              Expanded(
                child: Stack(
                  children: [
                    Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Text('COMMITMENTS', style: kInputFieldHeader),
                        const SizedBox(height: 10),
                        Expanded(
                          child: SizedBox(
                            height: 220,
                            child: Container(
                              child: commitments.isNotEmpty
                                  ? _buildCommitmentsList()
                                  : _buildEmptyCommitments(),
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(4),
                                border:
                                    Border.all(width: 1, color: Colors.grey),
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                    Positioned(
                        bottom: 10,
                        right: 10,
                        child: FloatingActionButton(
                            heroTag: const Text('newCommitment'),
                            child: const Icon(Icons.add, size: 30),
                            onPressed: () => _commitmentScreenNew())),
                  ],
                ),
              ),
              TextButton(
                  onPressed: () {
                    Navigator.pop(context);
                    widget.onDeleted(resolution);
                  },
                  child: const Text(
                    'DELETE RESOLUTION',
                  )),
            ],
          ),
        ),
      ),
    );
  }

And here's the listView builder method...

  _buildCommitmentsList() {
    return ListView.builder(
      itemCount: commitments.length,
      physics: const BouncingScrollPhysics(),
      itemBuilder: (context, index) {
        return Padding(
          padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
          child: ListTile(
            title: Text(commitments[index].description),
            tileColor: resolution.color,
            onTap: () => _commitmentScreenEdit(commitments[index]),
            onLongPress: () => _removeCommitment(commitments[index]),
          ),
        );
      },
    );
  }

Any help would be greatly appreciated :)


Solution

  • Just for the record, I eventually resolved this by replacing the ListTiles with coloured containers.