In the app, there is a button which pushes a page. This page contains a ListView.builder with more than 400 custom widgets. However, when the button is clicked, the app freezes for a few seconds and then pushes the page making the app lag.
I found the problem is in the loading state of those widgets. In fact, with “lighter” widgets (like simple text widgets) the app is still slowed down but not as when my custom widgets are loaded.
As far as I know, ListView.builder is a lazy widget, so shouldn’t it make the loading process easier to process?
I’ve already tried using a FutureBuilder first, and also pagination but they couldn’t solve the problem.
Here is the code of the page containing the ListView.builder:
class ExercisesListAdd extends ConsumerStatefulWidget {
const ExercisesListAdd({
super.key,
required this.workout,
required this.indexI,
required this.exercises,
});
final Workout workout;
final int? indexI;
final List<Exercise> exercises;
@override
ConsumerState<ExercisesListAdd> createState() => _ExercisesListAddState();
}
class _ExercisesListAddState extends ConsumerState<ExercisesListAdd> {
List<Exercise> get exercises => widget.exercises;
@override
Widget build(BuildContext context) {
final userP = ref.watch(userStateNotifier);
final exerciseP = ref.watch(exercisesProvider);
final exercisePnot = ref.watch(exercisesProvider.notifier);
final int? ind = widget.indexI;
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (userP.customExercises.isNotEmpty)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Text(
'Custom Exercises',
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 5),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Column(
children: [
const SizedBox(height: 5),
exerciseTile(
context,
userP.customExercises[index],
userP,
userP.customExercises[index].exType,
ind,
),
const SizedBox(height: 5)
],
);
},
itemCount: userP.customExercises.length,
),
],
),
const SizedBox(height: 10),
Text(
'All Exercises',
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 5),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return exerciseTile(
context,
exerciseP[index],
userP,
exerciseP[index].exType,
ind,
);
},
itemCount: exerciseP.length,
),
],
),
),
);
}
ListTile exerciseTile(BuildContext context, Exercise exercise, AppUser user,
ExerciseTypes type, int? ind) {
return ListTile(
contentPadding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
title: Text(
exercise.title,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
trailing: SizedBox(
width: MediaQuery.sizeOf(context).width / 3.2,
child: Text(
exercise.categories.join(', '),
textAlign: TextAlign.end,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color:
Theme.of(context).colorScheme.onBackground.withOpacity(.6),
),
),
),
onTap: () {
if (ind == null) {
widget.workout.exerciseList.add(
exercise.toPersonalExercise(type, user),
);
} else {
widget.workout.exerciseList.insert(
ind,
exercise.toPersonalExercise(type, user),
);
}
Navigator.pop(context, exercise);
},
);
}
}