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)