點燈坊

失くすものさえない今が強くなるチャンスよ

TabBar 實現 Tab 介面 (TabController)

Sam Xiao's Avatar 2024-11-14

簡單的 TabBar 可使用 DefaultTabController 實現,若要完全控制 TabBar,則可使用進階的 TabController

Flutter

tabbar01

  • Android 與 iOS 都成功使用 TabController 實現 TabBar

TabController

import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  const Home({super.key});

  
  State<Home> createState() => _Home();
}

class _Home extends State<Home> with SingleTickerProviderStateMixin {
  late TabController _tabController;

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

    _tabController.addListener(
      () async {
        if (_tabController.indexIsChanging) {
          switch (_tabController.index) {
            case 0:
              print('Car Tab');
              break;
            case 1:
              print('Train Tab');
              break;
            case 2:
              print('Bike Tab');
              break;
          }
        }
      },
    );
  }

  
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    var appBar = AppBar(
      title: const Text('TabBar with TabController'),
    );

    var tabBar = TabBar(
      controller: _tabController,
      tabs: const [
        Tab(text: 'Car'),
        Tab(text: 'Train'),
        Tab(text: 'Bike'),
      ],
    );

    var tabBarView = Expanded(
      child: TabBarView(
        controller: _tabController,
        children: const [
          Center(
            child: Text('Car Tab'),
          ),
          Center(
            child: Text('Train Tab'),
          ),
          Center(
            child: Text('Bike Tab'),
          ),
        ],
      ),
    );

    var body = Column(
      children: [
        tabBar,
        tabBarView,
      ],
    );

    return Scaffold(
      appBar: appBar,
      body: body,
    );
  }
}

Line 10

class _Home extends State<Home> with SingleTickerProviderStateMixin {
}
  • SingleTickerProviderStateMixin:要使用 TabController 時,則該 page 必須使用 SingleTickerProviderStateMixin mixin

Line 11

late TabController _tabController;
  • late:因為稍後會在 initState() 建立 _tabController,故宣告成 late 避免 Dart compiler 檢查

Line 13


void initState() {
  super.initState();
  _tabController = TabController(
    length: 3,
    vsync: this,
  );
}
  • _tabController:在 initSate() 內建立 TabController
    • length:設定 Tab 個數
    • vsync:可防止動畫在畫面不可見的時候進行無意義的更新,節省 CPU 和電池消耗。此處的 this 就是目前的 page

Line 21

_tabController.addListener(
  () async {
    if (_tabController.indexIsChanging) {
      switch (_tabController.index) {
        case 0:
          print('Car Tab');
          break;
        case 1:
          print('Train Tab');
          break;
        case 2:
          print('Bike Tab');
          break;
      }
    }
  },
);
  • 當 Tab 被點擊時所觸發的 event
  • _tabController.indexIsChanging:是否不同的 Tab 被點擊
  • _tabController.index:目前所點擊的 Tab

Line 52

var tabBar = TabBar(
  controller: _tabController,
  tabs: const [
    Tab(text: 'Car'),
    Tab(text: 'Train'),
    Tab(text: 'Bike'),
  ],
);
  • TabBar:建立 TabBar
    • controller:設定自訂的 TabController

Line 61

var tabBarView = Expanded(
  child: TabBarView(
    controller: _tabController,
    children: const [
      Center(
        child: Text('Car Tab'),
      ),
      Center(
        child: Text('Train Tab'),
      ),
      Center(
        child: Text('Bike Tab'),
      ),
    ],
  ),
);
  • TabBarView:建立 TabBarView
    • controller:設定自訂的 TabController

Line 40


void dispose() {
  _tabController.dispose();
  super.dispose();
}
  • dispose() 釋放自訂的 TabConrtroller

Conclusion

  • 若要使用自訂的 TabController,則 TabBarTabBarView 都必須指定 TabController,且必須在 dispose() 加以釋放