Flutter ListView scroll doesn't stop scrolling even when there is no content

Issue

ListView doesn’t stop scrolling when I reach the end of content, It keeps scrolling (not infinite scrolling).

How do I stop the scroll when there is no more content to scroll to?

Tried replacing ListView with Column –> didn’t work.

Tried adding SingleChildScrollView –> didn’t work.

Tried adding physics: NeverScrollableScrollPhysics() to ListView –> didn’t work.

Edit: Tried removing the Expanded widget –> didn’t work.

It is as there is extra height at the end, but there shouldn’t be anything.

Simplified code:

Expanded(
                    child: ListView(
                      children: [
                        Obx(() => Column()),
                        Obx(() => Text("Example")),
                        Row()
                      ],
                    ),
                  )

Gif of the problem:
https://imgur.com/a/MsZBanu

Also, in there is some gray overlay over the whole screen when the Flutter Inspector is working

Expanded(
            child: ListView(
              shrinkWrap: true,
              children: [
                Obx(
                  () => NameAndLocationWidget(
                    mountainsController: _mountainsController,

                    locationName: 'Lokacija',
                    name:
                        '${_mountainsController.mountain.value != null ? _mountainsController.mountain.value!.name : "-"}',
                    pathsController: null,
                    fontSize: AppFontSizes.aboutMountainTitle,
                  ),
                ),
                Obx(
                  () => Padding(
                    padding: const EdgeInsets.symmetric(
                        horizontal: AppPaddings
                            .aboutMountainMountainNameHorizontalPadding),
                    child: Text(
                      '${_mountainsController.mountain.value != null ? _mountainsController.mountain.value!.description : "-"}',
                      style: const TextStyle(
                        color: AppColors.aboutMountainDescriptionTextColor,
                        fontSize: AppFontSizes.aboutMountainDescriptionText,
                        height:
                            AppConstants.aboutMountainDescriptionTextHeight,
                      ),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(
                      horizontal: AppPaddings
                          .aboutMountainMountainNameHorizontalPadding,
                      vertical: AppPaddings
                          .aboutMountainMountainNameVerticalPadding),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      DistanceTimeDifficultyWidget(
                        dTDInfoName: 'distance'.tr,
                        dTDInfoValue: '6 - 10 km',
                      ),
                      DistanceTimeDifficultyWidget(
                        dTDInfoName: 'time'.tr,
                        dTDInfoValue: '2 - 4 h',
                      ),
                      DistanceTimeDifficultyWidget(
                        dTDInfoName: 'difficulty'.tr,
                        dTDInfoValue: 'Easy',
                      ),
                    ],
                  ),
                )
              ],
            ),
          )

Update:

The problem is not in the code above, but in the bottomNavigationBar:SlidingUpPanel()

SlidingUpPanel(
            backdropEnabled: true,
            backdropOpacity: 0.25,
            borderRadius: const BorderRadius.only(
                topLeft: Radius.circular(
                    AppConstants.aboutMountainSolidBottomSheetBorderRadius),
                topRight: Radius.circular(
                    AppConstants.aboutMountainSolidBottomSheetBorderRadius)),
            minHeight: MediaQuery.of(context).size.height * 0.1,
            maxHeight: MediaQuery.of(context).size.height * 0.75,
            controller: _pc,
            panel: Column(
              children: [
                SizedBox(
                  width: double.maxFinite,
                  child: ClipRRect(
                    borderRadius: const BorderRadius.only(
                      topRight: Radius.circular(AppConstants
                          .aboutMountainSolidBottomSheetBorderRadius),
                      topLeft: Radius.circular(AppConstants
                          .aboutMountainSolidBottomSheetBorderRadius),
                    ),
                    child: TextButton(
                        child: Column(
                          children: [
                            RotationTransition(
                              turns: Tween(begin: 0.0, end: 1.0)
                                  .animate(_controller),
                              child: const Icon(
                                Icons.expand_less,
                                color: AppColors
                                    .aboutMountainSolidBottomSheetTextColor,
                                size: AppFontSizes
                                    .aboutMountainSolidBottomSheetText,
                              ),
                            ),
                            Text(
                              "path_list".tr,
                              style: const TextStyle(
                                  color: AppColors
                                      .mountainsScreenBottomModalButtonColor,
                                  fontSize: AppFontSizes
                                      .mountainsScreenBottomModalButtonText),
                            )
                          ],
                        ),
                        onPressed: () {
                          FocusManager.instance.primaryFocus?.unfocus();
                          if (_pc.isPanelClosed) {
                            _controller.forward(from: 0.0);
                            _pc.open();
                          } else {
                            _controller.reverse(from: 0.5);
                            _pc.close();
                          }
                        }),
                  ),
                ),
                Container(
                  margin: const EdgeInsets.symmetric(
                      horizontal: AppConstants.bottomModalSheetSearchMarginHor,
                      vertical: AppConstants.bottomModalSheetSearchMarginVer),
                  decoration: BoxDecoration(
                    color: AppColors.searchBoxBackgroundColor,
                    borderRadius:
                        BorderRadius.circular(AppConstants.searchBoxRadius),
                  ),
                  child: SingleChildScrollView(
                    child: TextField(
                      onChanged: (value) {
                        _pathsController.searchPaths(SearchPathDto(
                            start: 0,
                            size: 10,
                            name: value,
                            mountainId: Get.parameters['id']!));
                        _pathsController.onClose();
                      },
                      decoration: InputDecoration(
                        hintStyle: const TextStyle(
                            fontSize: AppFontSizes.searchBoxHintText),
                        hintText: 'search'.tr,
                        suffixIcon: const Icon(
                          Icons.search,
                          color: AppColors.searchBoxSearchIconColor,
                        ),
                        border: InputBorder.none,
                        contentPadding:
                            const EdgeInsets.all(AppPaddings.searchBoxPadding),
                      ),
                    ),
                  ),
                ),
                Expanded(
                  child: Obx(
                    () => ListView.builder(
                      itemCount: _pathsController.paths.length,
                      scrollDirection: Axis.vertical,
                      itemBuilder: (context, index) {
                        final item = _pathsController.paths[index];
                        return PathCardBox(
                          path: item,
                        );
                      },
                    ),
                  ),
                ),
              ],
            ),
          )

It looks like it takes the whole screen (as you can see by the grey overlay in the Flutter Inspector), but it should only take the small amount when it’s collapsed.

Update(12.9.2022):

Changed the whole layout, now everything from Scaffold(body:) in inside SlidingUpPanel(body:), but the scroll isn’t working as well,

is there some SlidingUpPanel property that can conflict with the scroll?

Solution

body: Stack(
            children: [
              SlidingUpPanel(
                parallaxEnabled: true,
                backdropEnabled: true,
                backdropOpacity: 0.25,
                borderRadius: const BorderRadius.only(
                    topLeft: Radius.circular(
                        AppConstants.aboutMountainSolidBottomSheetBorderRadius),
                    topRight: Radius.circular(AppConstants
                        .aboutMountainSolidBottomSheetBorderRadius)),
                minHeight: MediaQuery.of(context).size.height * 0.1,
                maxHeight: MediaQuery.of(context).size.height * 0.75,
                controller: _pc,
                body: Column(
                  children: [
                    Obx(
                      () => Container(
                        height: MediaQuery.of(context).size.height * 0.4,
                        decoration: BoxDecoration(
                            borderRadius: const BorderRadius.only(
                                bottomLeft: Radius.circular(AppConstants
                                    .aboutMountainImageCardBorderRadius),
                                bottomRight: Radius.circular(AppConstants
                                    .aboutMountainImageCardBorderRadius)),
                            image: DecorationImage(
                                image: NetworkImage(
                                    '${_mountainsController.mountain.value != null ? _mountainsController.mountain.value!.imgUrl : "https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif?20151024034921"}'),
                                fit: BoxFit.fill)),
                      ),
                    ),
                    Container(
                      height: MediaQuery.of(context).size.height * 0.5,
                      child: SingleChildScrollView(
                        child: Column(
                          children: <Widget>[
                            Obx(
                              () => NameAndLocationWidget(
                                mountainsController: _mountainsController,

                                ///HARDCODED LOCATION
                                locationName: 'Lokacija',
                                name:
                                    '${_mountainsController.mountain.value != null ? _mountainsController.mountain.value!.name : "-"}',
                                pathsController: null,
                                fontSize: AppFontSizes.aboutMountainTitle,
                              ),
                            ),
                            Obx(
                              () => Padding(
                                padding: const EdgeInsets.symmetric(
                                    horizontal: AppPaddings
                                        .aboutMountainMountainNameHorizontalPadding),
                                child: Text(
                                  '${_mountainsController.mountain.value != null ? _mountainsController.mountain.value!.description : "-"}',
                                  style: const TextStyle(
                                    color: AppColors
                                        .aboutMountainDescriptionTextColor,
                                    fontSize: AppFontSizes
                                        .aboutMountainDescriptionText,
                                    height: AppConstants
                                        .aboutMountainDescriptionTextHeight,
                                  ),
                                ),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.symmetric(
                                  horizontal: AppPaddings
                                      .aboutMountainMountainNameHorizontalPadding,
                                  vertical: AppPaddings
                                      .aboutMountainMountainNameVerticalPadding),
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  /// HARDCODED EXTRA MOUNTAIN INFO
                                  DistanceTimeDifficultyWidget(
                                    dTDInfoName: 'distance'.tr,
                                    dTDInfoValue: '6 - 10 km',
                                  ),
                                  DistanceTimeDifficultyWidget(
                                    dTDInfoName: 'time'.tr,
                                    dTDInfoValue: '2 - 4 h',
                                  ),
                                  DistanceTimeDifficultyWidget(
                                    dTDInfoName: 'difficulty'.tr,
                                    dTDInfoValue: 'Easy',
                                  ),

                                  /// HARDCODED EXTRA MOUNTAIN INFO
                                ],
                              ),
                            )
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
                panel: Column(
                  children: [
                    SizedBox(
                      width: double.maxFinite,
                      child: ClipRRect(
                        borderRadius: const BorderRadius.only(
                          topRight: Radius.circular(AppConstants
                              .aboutMountainSolidBottomSheetBorderRadius),
                          topLeft: Radius.circular(AppConstants
                              .aboutMountainSolidBottomSheetBorderRadius),
                        ),
                        child: TextButton(
                            child: Column(
                              children: [
                                RotationTransition(
                                  turns: Tween(begin: 0.0, end: 1.0)
                                      .animate(_controller),
                                  child: Padding(
                                    padding: const EdgeInsets.symmetric(vertical: 10),
                                    child: Container(
                                      height: 8,
                                      width: 40,
                                        decoration: BoxDecoration(
                                          color: Colors.grey.shade400,
                                          borderRadius:
                                          BorderRadius.circular(AppConstants.searchBoxRadius),
                                        )
                                    ),
                                  ),
                                ),
                                Text(
                                  "path_list".tr,
                                  style: const TextStyle(
                                      color: AppColors
                                          .mountainsScreenBottomModalButtonColor,
                                      fontSize: AppFontSizes
                                          .mountainsScreenBottomModalButtonText),
                                )
                              ],
                            ),
                            onPressed: () {
                              FocusManager.instance.primaryFocus?.unfocus();
                              if (_pc.isPanelClosed) {
                                _controller.forward(from: 0.0);
                                _pc.open();
                              } else {
                                _controller.reverse(from: 0.5);
                                _pc.close();
                              }
                            }),
                      ),
                    ),
                    Container(
                      margin: const EdgeInsets.symmetric(
                          horizontal:
                              AppConstants.bottomModalSheetSearchMarginHor,
                          vertical:
                              AppConstants.bottomModalSheetSearchMarginVer),
                      decoration: BoxDecoration(
                        color: AppColors.searchBoxBackgroundColor,
                        borderRadius:
                            BorderRadius.circular(AppConstants.searchBoxRadius),
                      ),
                      child: SingleChildScrollView(
                        child: TextField(
                          onChanged: (value) {
                            _pathsController.searchPaths(SearchPathDto(
                                start: 0,
                                size: 10,
                                name: value,
                                mountainId: Get.parameters['id']!));
                            _pathsController.onClose();
                          },
                          decoration: InputDecoration(
                            hintStyle: const TextStyle(
                                fontSize: AppFontSizes.searchBoxHintText),
                            hintText: 'search'.tr,
                            suffixIcon: const Icon(
                              Icons.search,
                              color: AppColors.searchBoxSearchIconColor,
                            ),
                            border: InputBorder.none,
                            contentPadding: const EdgeInsets.all(
                                AppPaddings.searchBoxPadding),
                          ),
                        ),
                      ),
                    ),
                    Expanded(
                      child: Obx(
                        () => ListView.builder(
                          itemCount: _pathsController.paths.length,
                          scrollDirection: Axis.vertical,
                          itemBuilder: (context, index) {
                            final item = _pathsController.paths[index];
                            return PathCardBox(
                              path: item,
                            );
                          },
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              Positioned(
                  child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(
                        AppPaddings.aboutMountainFABPadding,
                        AppPaddings.aboutMountainFABPadding,
                        0,
                        0),
                    child: FloatingActionButton(
                      onPressed: () {
                        // Get.toNamed(AppRoutes.mountains);
                        Get.back();
                      },
                      heroTag: 'back_button',
                      backgroundColor:
                          AppColors.aboutMountainFABBackgroundColor,
                      child: const Icon(
                        Icons.arrow_back_ios_new,
                        color: AppColors.aboutMountainFABIconColor,
                      ),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(
                      0,
                      AppPaddings.aboutMountainFABPadding,
                      AppPaddings.aboutMountainFABPadding,
                      0,
                    ),
                    child: FloatingActionButton(
                      onPressed: () {
                        Get.toNamed(AppRoutes.home);
                      },
                      heroTag: 'home_button',
                      backgroundColor:
                          AppColors.aboutMountainFABBackgroundColor,
                      child: const Icon(
                        Icons.home,
                        color: AppColors.aboutMountainFABIconColor,
                      ),
                    ),
                  ),
                ],
              ))
            ],
          ),

You can see the gif here https://imgur.com/a/1M9fq1Z

Answered By – Lovro

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *