0

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 widget (which is the body of a Scaffold stored in another file) 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);
      },
    );
  }
}
8
  • you may remove physics: NeverScrollableScrollPhysics(), and layout shouldnt start with SingleChildScrollView Commented May 20, 2024 at 20:12
  • @Md.YeasinSheikh I missed saying that it is a widget of another page which contains the Scaffold. So the widget I posted is the body. Commented May 20, 2024 at 20:34
  • based on your code architecture, I would prefer customScrollView, also you can replace SingleChildScrollView with ListView and inner ListView with forLoop/mapping which will return the Column Commented May 20, 2024 at 20:38
  • You have used the shrinkWrap parameter. This renders all the elements of the list to calculate their size and then builds the list. If you remove this then the builder will load lazily. Commented May 21, 2024 at 2:36
  • I think you should use SliverList instead of ListView. Let's try it Commented May 21, 2024 at 3:40

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.