Call build on Text widget when i change tab

390

Inside the TabBar widget, add onTap callback with the setState method to trigger rebuild, hence updating the name:

...
appBar: AppBar(
  title: Text(tasksListLabels[_tabController.index].longName),
  bottom: TabBar(
    controller: _tabController,
    isScrollable: true,
    tabs: [
      Tab(text: tasksListLabels[0].shortName),
      Tab(text: tasksListLabels[1].shortName),
      Tab(text: tasksListLabels[2].shortName),
      Tab(text: tasksListLabels[3].shortName),
      Tab(text: tasksListLabels[4].shortName),
      Tab(text: tasksListLabels[5].shortName),
    ],
    onTap: (_) {
      setState((){});
    },
  ),
),
...
Share:
390
Miroslav Peterka
Author by

Miroslav Peterka

Updated on November 27, 2022

Comments

  • Miroslav Peterka
    Miroslav Peterka over 1 year

    I want to change title in appBar, when when I switch from one tab to another. In my current code do not do that because on change tab build is not called.

    Thanks to all!!

      
    
          import 'package:flutter/material.dart';
            import 'package:provider/provider.dart';
            
            import '../models/task.dart';
            import '../widgets/tasks_list_mob.dart';
            import '../widgets/new_task.dart';
            
            class TaskListName {
              final String shortName;
              final String longName;
              TaskListName(this.shortName, this.longName);
            }
            
            class TaksScreen extends StatefulWidget {
              @override
              _TaksScreenState createState() => _TaksScreenState();
            }
            
            class _TaksScreenState extends State with TickerProviderStateMixin {
              TabController _tabController;
              final Map tasksListLabels = {
                0: TaskListName('Backlog', 'Tasks in backlog'),
                1: TaskListName('Tomorrow', 'Planed tasks for tomorrow'),
                2: TaskListName('Today', 'Your tasks for today'),
                3: TaskListName('Last work day', 'Tasks completed last working day'),
                4: TaskListName('Completed', 'Completed Tasks'),
                5: TaskListName('Backlog', 'Archived not completed tasks'),
              };
            
              @override
              void initState() {
                super.initState();
                _tabController = TabController(length: 6, vsync: this, initialIndex: 2);
              }
            
              @override
              void dispose() {
                _tabController.dispose();
                super.dispose();
              }
            
              Future showAddTaskDialog(BuildContext context) async {
                print(_tabController);
                await showDialog(
                  context: context,
                  builder: (context) => SimpleDialog(
                    children: [NewTask(TaksBucket.backlog)],
                  ),
                );
              }
            
              @override
              Widget build(BuildContext context) {
                final tasks = Provider.of>(context);
                return Scaffold(
                  appBar: AppBar(
                    title: Text(tasksListLabels[_tabController.index].longName),
                    bottom: TabBar(
                      controller: _tabController,
                      isScrollable: true,
                      tabs: [
                        Tab(text: tasksListLabels[0].shortName),
                        Tab(text: tasksListLabels[1].shortName),
                        Tab(text: tasksListLabels[2].shortName),
                        Tab(text: tasksListLabels[3].shortName),
                        Tab(text: tasksListLabels[4].shortName),
                        Tab(text: tasksListLabels[5].shortName),
                      ],
                    ),
                  ),
                  body: TabBarView(
                    controller: _tabController,
                    children: [
                      TasksListMob(tasks, TaksBucket.backlog),
                      TasksListMob(tasks, TaksBucket.tomorrow),
                      TasksListMob(tasks, TaksBucket.today),
                      TasksListMob(tasks, TaksBucket.completed),
                      TasksListMob(tasks, TaksBucket.completed),
                      TasksListMob(tasks, TaksBucket.archived),
                    ],
                  ),
                  floatingActionButton: FloatingActionButton(
                    child: Icon(Icons.add),
                    onPressed: () => showAddTaskDialog(context),
                  ),
                  floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
                );
              }
            }
        
        

    After @mkobuolys solution implementation - scroll handle is still missinng...

    
        import 'package:flutter/material.dart';
        import 'package:provider/provider.dart';
        
        import '../models/task.dart';
        import '../widgets/tasks_list_mob.dart';
        import '../widgets/new_task.dart';
        
        class TaskListName {
          final String shortName;
          final String longName;
          TaskListName(this.shortName, this.longName);
        }
        
        class TaksScreen extends StatefulWidget {
          @override
          _TaksScreenState createState() => _TaksScreenState();
        }
        
        class _TaksScreenState extends State with TickerProviderStateMixin {
          TabController _tabController;
          var _tabIndex = ValueNotifier(2);
          final Map tasksListLabels = {
            0: TaskListName('Backlog', 'Tasks in backlog'),
            1: TaskListName('Tomorrow', 'Planed tasks for tomorrow'),
            2: TaskListName('Today', 'Your tasks for today'),
            3: TaskListName('Last work day', 'Tasks completed last working day'),
            4: TaskListName('Completed', 'Completed Tasks'),
            5: TaskListName('Backlog', 'Archived not completed tasks'),
          };
        
          @override
          void initState() {
            super.initState();
            _tabController = TabController(length: 6, vsync: this, initialIndex: 2);
          }
        
          Future showAddTaskDialog(BuildContext context) async {
            await showDialog(
              context: context,
              builder: (context) => SimpleDialog(
                children: [NewTask(TaksBucket.backlog)],
              ),
            );
          }
        
          @override
          Widget build(BuildContext context) {
            final tasks = Provider.of>(context);
            return Scaffold(
              appBar: AppBar(
                title: **ValueListenableBuilder(
                  valueListenable: _tabIndex,
                  builder: (context, value, child) =>
                      Text(tasksListLabels[value].longName),
                ),**
                bottom: TabBar(
                  controller: _tabController,
                  isScrollable: true,
                  onTap: (value) {
                    _tabIndex.value = _tabController.index;
                  },
                  tabs: [
                    Tab(text: tasksListLabels[0].shortName),
                    Tab(text: tasksListLabels[1].shortName),
                    Tab(text: tasksListLabels[2].shortName),
                    Tab(text: tasksListLabels[3].shortName),
                    Tab(text: tasksListLabels[4].shortName),
                    Tab(text: tasksListLabels[5].shortName),
                  ],
                ),
              ),
              body: TabBarView(
                controller: _tabController,
                children: [
                  TasksListMob(tasks, TaksBucket.backlog),
                  TasksListMob(tasks, TaksBucket.tomorrow),
                  TasksListMob(tasks, TaksBucket.today),
                  TasksListMob(tasks, TaksBucket.completed),
                  TasksListMob(tasks, TaksBucket.completed),
                  TasksListMob(tasks, TaksBucket.archived),
                ],
              ),
              floatingActionButton: FloatingActionButton(
                child: Icon(Icons.add),
                onPressed: () => showAddTaskDialog(context),
              ),
            );
          }
        }
    
    

    At the end it was really easy to make it done!

    • I did create ValueNotifier _tabIndex

    • At init state I addListener on TabControler. Listener set value for _tabIndex(ValueNotifier). I did dispose Listener in dispose...

    • In build method add ValueListenableBuilder to title.

    • Final code:

        import 'package:flutter/material.dart';
        import 'package:provider/provider.dart';
      
        import '../models/task.dart';
        import '../widgets/tasks_list_mob.dart';
        import './tasks_notifications_screen.dart';
        import '../widgets/new_task.dart';
        import '../widgets/count_batch_icon_button.dart';
        import '../consts/consts.dart';
        import '../util/tasks_helper.dart';
      
        class TaskListName {
          final String shortName;
          final String longName;
          final TaksBucket bucket;
          TaskListName(this.shortName, this.longName, this.bucket);
        }
      
        class TaksScreen extends StatefulWidget {
          @override
          _TaksScreenState createState() => _TaksScreenState();
        }
      
        class _TaksScreenState extends State with TickerProviderStateMixin {
          TabController _tabController;
          var _tabIndex = ValueNotifier(2);
      
          final Map tasksListLabels = {
            0: TaskListName('Backlog', 'Tasks in backlog', TaksBucket.backlog),
            1: TaskListName(
                'Tomorrow', 'Planed tasks for tomorrow', TaksBucket.tomorrow),
            2: TaskListName('Today', 'Your tasks for today', TaksBucket.today),
            3: TaskListName('Last work day', 'Tasks completed last working day',
                TaksBucket.completed),
            4: TaskListName('Completed', 'Completed Tasks', TaksBucket.completed),
            5: TaskListName(
                'Archived', 'Archived not completed tasks', TaksBucket.archived),
          };
      
          @override
          void initState() {
            super.initState();
            _tabController = TabController(length: 6, vsync: this, initialIndex: 2);
            _tabController.addListener(() {
              _tabIndex.value = _tabController.index;
            });
          }
      
          @override
          void dispose() {
            super.dispose();
            _tabController.removeListener(() {
              _tabIndex.value = _tabController.index;
            });
          }
      
          Future showAddTaskDialog(BuildContext context) async {
            await showDialog(
              context: context,
              builder: (context) => SimpleDialog(
                children: [NewTask(tasksListLabels[_tabController.index].bucket)],
              ),
            );
          }
      
          @override
          Widget build(BuildContext context) {
            final tasks = Provider.of>(context);
            return Scaffold(
              appBar: AppBar(
                title: ValueListenableBuilder(
                  valueListenable: _tabIndex,
                  builder: (context, value, child) =>
                      Text(tasksListLabels[value].longName),
                ),
                actions: [
                  CountBatchIconButton(
                    TasksHelper.numberOfTasksForNotification(tasks),
                    Icon(Icons.notifications_none),
                    () => Navigator.of(context).pushNamed(TasksNotifications.routeName),
                  ),
                ],
                bottom: TabBar(
                  controller: _tabController,
                  isScrollable: true,
                  indicatorColor: TaskConsts.mainColor,
                  tabs: [
                    Tab(text: tasksListLabels[0].shortName),
                    Tab(text: tasksListLabels[1].shortName),
                    Tab(text: tasksListLabels[2].shortName),
                    Tab(text: tasksListLabels[3].shortName),
                    Tab(text: tasksListLabels[4].shortName),
                    Tab(text: tasksListLabels[5].shortName),
                  ],
                ),
              ),
              body: TabBarView(
                controller: _tabController,
                children: [
                  TasksListMob(tasks, TaksBucket.backlog),
                  TasksListMob(tasks, TaksBucket.tomorrow),
                  TasksListMob(tasks, TaksBucket.today),
                  TasksListMob(
                    tasks,
                    TaksBucket.completed,
                    isLastWorkingDay: true,
                  ),
                  TasksListMob(tasks, TaksBucket.completed),
                  TasksListMob(tasks, TaksBucket.archived),
                ],
              ),
              floatingActionButton: FloatingActionButton(
                backgroundColor: TaskConsts.mainColor,
                child: Icon(Icons.add),
                onPressed: () => showAddTaskDialog(context),
              ),
            );
          }
        }
        
  • Miroslav Peterka
    Miroslav Peterka almost 3 years
    That partialy work :-). Thank you @mkobuolys! I did use ValueNotifier instead of set state, but It still not handle scroll event. I did update original post.
  • mkobuolys
    mkobuolys almost 3 years
    If you want to change the tab view (with scroll), you can use _tabController.animateTo(newIndex, Duration(seconds: 2), curve: Curves.easeInOut) where newIndex is the index of the tab you want to go to (just adjust parameters based on your needs, of course).
  • Miroslav Peterka
    Miroslav Peterka almost 3 years
    I did enable it with isScrollable: true, on TabBar. My problem is how to build title on scroll.
  • tomerpacific
    tomerpacific over 2 years
    This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review