Home > Software engineering >  How to detect TabBar child focus changed in flutter
How to detect TabBar child focus changed in flutter

Time:10-12

I'm developing an App for TV by Flutter.

I need to detect the focus change event of TabBar child, how can I do that? This is a sample code:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class TabBarSample extends StatefulWidget {
  const TabBarSample({Key? key}) : super(key: key);
  @override
  State<TabBarSample> createState() => _TabBarSampleState();
}

class _TabBarSampleState extends State<TabBarSample>
    with TickerProviderStateMixin{
  late TabController _tabController;
  final _tabs = ['Tab 01','Tab 02','Tab 03','Tab 04','Tab 05','Tab 06','Tab 07','Tab 08'];
  @override
  Widget build(BuildContext context) {
    _tabController = TabController(length: _tabs.length, vsync: this);
    return Scaffold(
      body: Center(
        child: Container(
            child: TabBar(
              labelColor: Colors.blue,
              labelStyle: TextStyle(color: Colors.blue, fontSize: 36),
              unselectedLabelColor: Colors.black54,
              unselectedLabelStyle: TextStyle(color: Colors.black, fontSize: 36),
              isScrollable: true,
              indicator: BoxDecoration(
                  color: Colors.greenAccent,
                  borderRadius: BorderRadius.all(Radius.circular(12))),
              controller: _tabController,
              // onTap: _changeTab,
              tabs: _tabs.map((e) => Tab(
                  height: 36,
                  text: e)).toList(),
            )
        ),
      )
    );
  }
}

enter image description here

In this screenshot, how can I know 'Tab 06' is focused?

Thank you.

Update:

I changed the child of TabBar from Tab widget to Focus Widget, and tried to do something in the child's onFocusChange callback,like this:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class TabBarFocusSample extends StatefulWidget {
  const TabBarFocusSample({Key? key}) : super(key: key);
  @override
  State<TabBarFocusSample> createState() => _TabBarFocusSampleState();
}

class _TabBarFocusSampleState extends State<TabBarFocusSample>
    with TickerProviderStateMixin{
  late TabController _tabController;
  final _tabs = ['Tab 01','Tab 02','Tab 03','Tab 04','Tab 05','Tab 06','Tab 07','Tab 08'];
  @override
  Widget build(BuildContext context) {
    _tabController = TabController(length: _tabs.length, vsync: this);
    return Scaffold(
      body: Center(
        child: Container(
            child: TabBar(
              labelColor: Colors.blue,
              labelStyle: TextStyle(color: Colors.blue, fontSize: 36),
              unselectedLabelColor: Colors.black54,
              unselectedLabelStyle: TextStyle(color: Colors.black, fontSize: 36),
              isScrollable: true,
              indicator: BoxDecoration(
                  color: Colors.greenAccent,
                  borderRadius: BorderRadius.all(Radius.circular(12))),
              controller: _tabController,
              // onTap: _changeTab,
              tabs: _tabs.map((e) => Focus(
                  onFocusChange: (focused) {
                    print('tab onFocusChange,$focused, ${e}');
                    if (focused) {
                       _changeTabByCode(e);
                    }
                  },
                  child: Tab(text: e,height: 40,))).toList(),
            )
        ),
      )
    );
  }

  void _changeTabByCode(String pageCode) {
    print("_changeTabByCode,$pageCode");
    var navIndex = _tabs.indexWhere((element) => element == pageCode)?? 0;;
    _tabController.animateTo(navIndex, duration: const Duration(microseconds: 300), curve: Curves.ease);
  }
}

but there's a new problem, the onFocusChange function won't be called sometimes.

enter image description here

In this screenshot, I can't animateTo tab01 by arrow key.

===================== update:

change Focus to FocusableActionDetector, the same result, like this:

enter image description here

CodePudding user response:

I belive if you use FocusableActionDetector you can solve this problem

CodePudding user response:

You can use a TabController and add a callback using addListener. For example:

 @override
  void initState() {
    super.initState();
    _tabController = TabController(vsync: this, length: myTabs.length);

    _tabController.addListener(_handleTabSelection);
  }

void _handleTabSelection() {
    if (_tabController.indexIsChanging) {
      switch (_tabController.index) {
        case 0:
          Scaffold.of(_context).showSnackBar(SnackBar(
            content: Text('Page 1 tapped.'),
            duration: Duration(milliseconds: 500),
          ));
          break;
        case 1:
          Scaffold.of(_context).showSnackBar(SnackBar(
            content: Text('Page 2 tapped.'),
            duration: Duration(milliseconds: 500),
          ));
          break;
      }
    }
  }
  • Related