skip to Main Content

I have implemented a TabBar in my Flutter application in which each individual tab represents a day that the user wants to work out and the tab’s text is the title of the day. Days are stored in a list. My problem is changing a day’s title in the list, changes other tabs’ texts as well. Take a look at my code.

This is my WorkoutDay class.

class WorkoutDay {
  List<Exercise>? exercises;
  String title = 'Workout Day';
  WorkoutDay.newEmptyDay();
  WorkoutDay(this.title, this.exercises);
}

I have a list of workout days.

List<WorkoutDays> workoutDays;

And I have a TabBar which tabs are the title of workout days. I generate the tabs this way.

tabs: List.generate(workoutDays.length, (index) => Tab(text: workoutDays[index].title))

The problem is that workoutDays[0].title = 'new title'; applies to all the other tabs as well.

What is the problem?!

I will share the whole dart file below. Thanks.

import 'package:extrain/ui/views/add_exercise_tab_view.dart';
import 'package:extrain/utilities/enums/purposes.dart';
import 'package:extrain/utilities/models/exercise.dart';
import 'package:extrain/utilities/models/workout_day.dart';
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'package:provider/provider.dart';
import 'dart:developer';

class NewManualWorkout extends StatefulWidget {
  const NewManualWorkout({Key? key}) : super(key: key);

  @override
  State<NewManualWorkout> createState() => _NewManualWorkoutState();
}

class _NewManualWorkoutState extends State<NewManualWorkout>
    with TickerProviderStateMixin {
  late TabController _tabController;
  String _dropdownValue = Purpose.values.first.text;
  double _currentSliderValue = 1;
  bool _restWarningVisibility = false;
  late List<WorkoutDay> workoutDays;

  @override
  void initState() {
    super.initState();
    workoutDays = [WorkoutDay.newEmptyDay()];
    _tabController = TabController(length: workoutDays.length, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: SingleChildScrollView(
        child: Column(
          children: [
            Card(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  /** Assigning new name here for example **/
                  ElevatedButton(
                      onPressed: () {
                        setState(() {
                          workoutDays[0].title = 'New Name';
                        });
                      }, child: const Text('Assign new name')),
                  Slider(
                    value: _currentSliderValue,
                    max: 7,
                    min: 1,
                    divisions: 6,
                    label: _currentSliderValue.round() == 1
                        ? '${_currentSliderValue.round().toString()} day in a week'
                        : '${_currentSliderValue.round().toString()} days in a week',
                    onChanged: (double value) {
                      setState(() {
                        _currentSliderValue = value;
                        workoutDays = List<WorkoutDay>.filled(
                            _currentSliderValue.round(),
                            WorkoutDay.newEmptyDay());
                        _tabController = TabController(
                            length: workoutDays.length, vsync: this);
                      });
                    },
                  ),
                ],
              ),
            ),
            Card(
              semanticContainer: true,
              clipBehavior: Clip.antiAlias,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10)),
              child: Column(
                children: [
                  Material(
                    color: Colors.blue,
                    child: SizedBox(
                      width: double.infinity,
                      child: Align(
                        alignment: Alignment.center,
                        child: TabBar(
                            controller: _tabController,
                            isScrollable: true,
                            tabs: List.generate(
                                workoutDays.length,
                                (index) => Tab(
                                      text: workoutDays[index].title,
                                    ))),
                      ),
                    ),
                  ),
                  SizedBox(
                    height: 300,
                    child: TabBarView(
                        controller: _tabController,
                        children: List.generate(
                            workoutDays.length,
                            (currentDay) => const Center(
                                  child: AddExerciseTabView(),
                                ))),
                  ),
                ],
              ),
            )
          ],
        ),
      )),
    );
  }
}

2

Answers


  1. its because of the way you instantiate the workoutDays
    in your Slider onChanged .

    Your general approach for the

    setState(() {
       workoutDays[0].title = 'New Name';
    });
    

    and the

    tabs: List.generate(workoutDays.length, (index) => Tab(text: workoutDays[index].title))
    

    is totally fine.

    just move the handling of the list to outside the build method
    (currently you reset your list every build with workoutDays = List<WorkoutDay>.filled(... ).

    Login or Signup to reply.
  2. You could try like this

    @override
    Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: SingleChildScrollView(
        child: Column(
          children: [
            Card(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  /** Assigning new name here for example **/
                  ElevatedButton(
                      onPressed: () {
                        workoutDays[0].title = 'New Name';
                        setState(() {});
                      },
                      child: const Text('Assign new name')),
                  Slider(
                    value: _currentSliderValue,
                    max: 7,
                    min: 1,
                    divisions: 6,
                    label: _currentSliderValue.round() == 1
                        ? '${_currentSliderValue.round().toString()} day in a week'
                        : '${_currentSliderValue.round().toString()} days in a week',
                    onChanged: (double value) {
                      _currentSliderValue = value;
                      workoutDays = List<WorkoutDay>.generate(
                          _currentSliderValue.round(), (i) {
                        return WorkoutDay.newEmptyDay();
                      }, growable: false);
                      _tabController = TabController(
                          length: workoutDays.length, vsync: this);
                      setState(() {});
                    },
                  ),
                ],
              ),
            ),
            Card(
              semanticContainer: true,
              clipBehavior: Clip.antiAlias,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10)),
              child: Column(
                children: [
                  Material(
                    color: Colors.blue,
                    child: SizedBox(
                      width: double.infinity,
                      child: Align(
                        alignment: Alignment.center,
                        child: TabBar(
                            controller: _tabController,
                            isScrollable: true,
                            tabs: List.generate(
                                workoutDays.length,
                                (index) => Tab(
                                      text: workoutDays[index].title,
                                    ))),
                      ),
                    ),
                  ),
                  SizedBox(
                    height: 300,
                    child: TabBarView(
                        controller: _tabController,
                        children: List.generate(
                            workoutDays.length,
                            (currentDay) => Center(
                                  child: Container(),
                                ))),
                  ),
                ],
              ),
            )
          ],
        ),
      )),
    );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search