จัดการ Tab ด้วย TabController ใน Flutter

บทความใหม่ เดือนที่แล้ว โดย Ninenik Narkdee
tabcontroller tab tabbarview tabbar

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ tabcontroller tab tabbarview tabbar



เนื้อหานี้มาดูเกี่ยวกับการใช้งาน tab ใน flutter ซึ่งเป็นรูปแบบ
การใช้งานที่พบเห็นได้บ่อยใน app ใน flutter เราสามารถกำหนด
และเรียกใช้งาน tab ด้วยขั้นตอนง่ายๆ ทำให้เราสะดวกในการนำ
มาจัดรูปแบบเลเอาท์ app ของเรา
    *ใช้เนื้อหาต่อเนื่องจากบทความ http://niik.in/961
 
 

การใช้งาน TabController

    TabController จะทำหน้าที่ในการประสานการทำงานของ tab ที่เลือก กับเนื้อหาของ
tab นั้นให้เป็นไปอย่างสอดคล้องกัน (จัดการระหว่าง TabBar กับ TabBarView ให้สัมพันธ์กัน) 
เช่น เลือก tab แรก ก็แสดงเนื้อหาของ tab แรก แบบนี้เป็นต้น เราสามารถสร้าง TabController 
แบบกำหนดเอง หรือจะใช้งาน DefaultTabController widget ก็ทำได้ง่ายๆ ในที่นี้ 
จะแนะนำทั้งสองรูปแบบ 
 
 

การสร้าง Tab โดยใช้ DefaultTabController widget

    การใช้งาน DefaultTabController widget เพื่อสร้าง tab มีรูปแบบการกำหนดง่ายๆ ดังนี้
 
DefaultTabController(
  length: 4, // จำนวน tab และเนื้อหา tab ที่ต้องการแสดง
  child: // ครอบ Scaffold widget 
);
 
    มาดูส่วนของ _HomeState ก่อนใช้งาน DefaultTabController
 
class _HomeState extends State<Home> {
  
    @override
    Widget build(BuildContext context) {
  
        return Scaffold(
            appBar: AppBar(
                title: Text('Home'),
            ),
            body: Center(
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                        Text('Home Screen'),
                    ],
                )
            ),
        );
    }
}
 
    เมื่อกำหนดใช้งาน DefaultTabController จะได้เป็นดังนี้
 
class _HomeState extends State<Home> {

    @override
    Widget build(BuildContext context) {
  
        return DefaultTabController( // ใช้งาน DefaultTabController
          length: 4, // กำหนดจำนวน tab
          child: Scaffold(
            appBar: AppBar(
              bottom: const TabBar( // ส่วนของ tab
                tabs: [
                  Tab(icon: Icon(Icons.feed)),
                  Tab(icon: Icon(Icons.favorite_sharp)),
                  Tab(icon: Icon(Icons.thumb_up)),
                  Tab(icon: Icon(Icons.announcement)),
                ],
              ),              
              title: Text('Home'),
            ),
            body: const TabBarView( // ส่วนของเนื้อหา tab
              children: [
                Center(child: Text('Tab 1111')),
                Center(child: Text('Tab 2222')),
                Center(child: Text('Tab 3333')),
                Center(child: Text('Tab 4444')),
              ],
            ),
          ),
        );
    }
}
 
    ผลลัพธ์ที่ได้

 
 


 
 
 

    การสร้าง TabBar

    จะเห็นว่าเราทำการสร้าง TabBar ในส่วนของ bottom property ของ AppBar 
 
bottom: const TabBar( // ส่วนของ tab
  tabs: [
    Tab(icon: Icon(Icons.feed)),
    Tab(icon: Icon(Icons.favorite_sharp)),
    Tab(icon: Icon(Icons.thumb_up)),
    Tab(icon: Icon(Icons.announcement)),
  ],
), 
 
    สามารถกำหนดเป็นไอคอนอย่างเดียว ข้อความอย่างเดียว หรือกำหนดทั้งสองอย่าง ก็ได้เช่น
 
bottom: const TabBar( // ส่วนของ tab
  tabs: [
    Tab(icon: Icon(Icons.feed),text:'Tab 1'),
    Tab(icon: Icon(Icons.favorite_sharp),text:'Tab 2'),
    Tab(icon: Icon(Icons.thumb_up),text:'Tab 3'),
    Tab(icon: Icon(Icons.announcement),text:'Tab 4'),
  ],
),    
 
    ผลลัพธ์ที่ได้

 
 


 
 
    

    การสร้าง TabBarView

    สำหรับการใช้งาน TabBarView เราก็กำหนดในส่วนของ body property ของ Scaffold
ในตัวอย่างจะกำหนดแสดงแค่ข้อความตรงกลางจอเพื่อจำลองการแสดงผล
 
body: const TabBarView( // ส่วนของเนื้อหา tab
  children: [
    Center(child: Text('Tab 1111')),
    Center(child: Text('Tab 2222')),
    Center(child: Text('Tab 3333')),
    Center(child: Text('Tab 4444')),
  ],
),
 
    เราสามารถประยุกต์โดยสร้างหน้า screen เพื่อมาแสดงเป็นเนื้อหาของ tab ที่ต้องการได้ ซึ่งถ้ามองแล้ว
ก็จะคล้ายๆ กับการใช้งาน BottomNavigationBar ของเมนูด้านล่าง app 
    ดูตัวอย่างการแสดงเนื้อหา app จาก screen หน้าอื่นๆ
 
body: const TabBarView( // ส่วนของเนื้อหา tab
  children: [
    About(),
    Profile(),
    Contact(),
    Settings(),                
  ],
),
 
    ผลลัพธ์ที่ได้

 
 


 
 
 
    โดยทั่วไป เมื่อใช้งาน DefaultTabController เรามักจะไม่ค่อยต้องการจัดการกับ TabController มากนัก
แต่อย่างไรก็ตาม หากต้องการให้สามารถใช้งาน TabController ทำงานร่วมกับการใช้งาน DefaultTabController 
ก็สามารถกำหนดได้ดังนี้
 
class _HomeState extends State<Home> {

    @override
    Widget build(BuildContext context) {
  
        return DefaultTabController( // ใช้งาน DefaultTabController
          length: 4, // กำหนดจำนวน tab
          child: Builder(builder: (BuildContext context) {
              return Scaffold(
// ........ ส่วนอื่นๆ เพิ่มเติม.....
            );
          }),
        );
    }
}
 
    เราใช้ Builder ซึ่งเป็น stateless widget ที่มีคำสั่ง build สำหรับสร้าง widget child ขึ้นมาใช้งาน
เราจะกำหนดการเรียกใช้งาน TabController ก่อนการ return Scaffold ดังนี้
 
class _HomeState extends State<Home> {

    @override
    Widget build(BuildContext context) {
  
        return DefaultTabController( // ใช้งาน DefaultTabController
          length: 4, // กำหนดจำนวน tab
          child: Builder(builder: (BuildContext context) {
              // เรียกใช้งาน TabController
              final TabController tabController = DefaultTabController.of(context)!;
              tabController.addListener(() { // ตรวจจับการทำงาน
                if (!tabController.indexIsChanging) { // มีการเปลี่ยน tab
                  // กำหนดคำสั่งตรงนี้
                  // tabController.animateTo(3); ไปยัง tab ที่กำหนด      
                  // tabController.index ค่า index ที่เปลี่ยน
                  // tabController.previousIndex ค่า index ก่อนเปลี่ยน
                  print(tabController.index);
                  print(tabController.previousIndex);
                }
              });            
              return Scaffold(
// ........ ส่วนอื่นๆ เพิ่มเติม.....
            );
          }),
        );
    }
}
 
    เราสามารถกำหนดเงื่อนไขการทำงานต่างๆ เมื่อเปลี่ยน tab ได้ ค่า index ของ tab จะเริ่มนับจาก 0
สำหรับ tab แรก และ tab สุดท้าย มี index คำนวณได้จากค่า tabController.length - 1
 
    เราสามารถทำคำสั่งให้ tab เลื่อนไปยังค่าที่ต้องการได้ผ่านการเรียกใช้งาน TabController ตัวอย่าง
เช่น เราสร้างปุ่มในเนื้อหาของ tab แรก แล้วเมื่อกดปุ่มนั้น ก็ให้เลื่อนไปยัง tab ที่ 4 ตามตัวอย่างดังนี้ได้
 
class _HomeState extends State<Home> {

    @override
    Widget build(BuildContext context) {
  
        return DefaultTabController( // ใช้งาน DefaultTabController
          length: 4, // กำหนดจำนวน tab
          child: Builder(builder: (BuildContext context) {
              // เรียกใช้งาน TabController
              final TabController tabController = DefaultTabController.of(context)!;
              tabController.addListener(() { // ตรวจจับการทำงาน
                if (!tabController.indexIsChanging) { // มีการเปลี่ยน tab
                  // กำหนดคำสั่งตรงนี้
                  // tabController.animateTo(3); ไปยัง tab ที่กำหนด            
                  // tabController.index ค่า index ที่เปลี่ยน
                  // tabController.previousIndex ค่า index ก่อนเปลี่ยน
                  print(tabController.index);
                  print(tabController.previousIndex);
                }
              });            
              return Scaffold(
                appBar: AppBar(
                  bottom: const TabBar( // ส่วนของ tab
                    tabs: [
                      Tab(icon: Icon(Icons.feed),text:'Tab 1'),
                      Tab(icon: Icon(Icons.favorite_sharp),text:'Tab 2'),
                      Tab(icon: Icon(Icons.thumb_up),text:'Tab 3'),
                      Tab(icon: Icon(Icons.announcement),text:'Tab 4'),
                    ],
                  ),              
                  title: Text('Home'),
                ),
                body: TabBarView( // ส่วนของเนื้อหา tab
                  children: [  
                    Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Text('Tab 1111'),
                          ElevatedButton( // ปุ่มสำหรับทดสอบ
                            onPressed: () {
                              // เลื่อนไปยัง index 3 ซึ่งก็คือค่า index ของ tab ที่ 4
                              tabController.animateTo(3);
                            },
                            child: const Text('Go to Tab 4'),
                          ),
                        ],
                      ),
                    ),
                    Center(child: Text('Tab 2222')),
                    Center(child: Text('Tab 3333')),
                    Center(child: Text('Tab 4444')),
                  ],
                ),
            );
          }),
        );
    }
}
 
 
    ผลลัพธ์ที่ได้

 
 


 
 
 
 

การสร้าง Tab โดยใช้ TabController แบบกำหนดเอง

    กรณีที่เราไม่ได้ใช้งาน DefaultTabController widget และต้องการกำหนดรูปแบบการใช้งาน
TabController แบบกำหนดเอง เพื่อให้สามารถจัดการ tab ได้ตามต้องการ สามารถทำได้ดังนี้
 
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {

    // กำหนดตัวแปร สำหรับเป็น ใช้งาน TabController
    // late keyword เป็นส่วนของการกำหนด ภาษา dart ที่ป้องกัน Null safety
    // เป็นการบอกว่า เราจะกำหนดค่าให้กับตัวแปรนี้แน่นอน จะไม่ปล่อยให้เป็น null 
    late TabController _tabController;

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

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

    @override
    Widget build(BuildContext context) {
  
        return Scaffold(
          appBar: AppBar(
            bottom: TabBar( // ส่วนของ tab
              controller: _tabController, // กำหนดการเรียกใช้งาน TabController
              tabs: [
                Tab(icon: Icon(Icons.feed),text:'Tab 1'),
                Tab(icon: Icon(Icons.favorite_sharp),text:'Tab 2'),
                Tab(icon: Icon(Icons.thumb_up),text:'Tab 3'),
                Tab(icon: Icon(Icons.announcement),text:'Tab 4'),
              ],
            ),              
            title: Text('Home'),
          ),
          body: TabBarView( // ส่วนของเนื้อหา tab
            controller: _tabController, // กำหนดการเรียกใช้งาน TabController
            children: [  
              Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text('Tab 1111'),
                    ElevatedButton( // ปุ่มสำหรับทดสอบ
                      onPressed: () {
                        // เลื่อนไปยัง index 3 ซึ่งก็คือค่า index ของ tab ที่ 4
                       _tabController.animateTo(3);
                      },
                      child: const Text('Go to Tab 4'),
                    ),
                  ],
                ),
              ),
              Center(child: Text('Tab 2222')),
              Center(child: Text('Tab 3333')),
              Center(child: Text('Tab 4444')),
            ],
          ),
      );
    }
}
 
 
    ผลลัพธ์ที่ได้ก็จะเหมือนตัวอย่างล่าสุดของแบบที่ใช้ DefaultTabController widget
    สิ่งที่เพิ่มเข้ามา เมื่อมีการใช้งาน TabController แบบกำหนดเอง
 
    - ส่วนของการใช้งาน State เราต้องกำหนดเรียกใช้ Mixin เพิ่มเข้าไปดังนี้
 
// class _HomeState extends State<Home> { // ค่าเดิม
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
 
    - กำหนดตัวแปร
 
late TabController _tabController;
 
    - กำหนดการควบคุม และค่าเริ่มต้นใน State
 
@override
void initState() {
  super.initState(); 
  // กำหนดค่าเริ่มต้น
  _tabController = TabController(length: 4,vsync: this);    
} 

@override
void dispose() {
  _tabController.dispose();
  super.dispose();
}   
 
    - ส่วนสุดท้ายกำหนด controller ให้กับ TabBar และ TabBarView
 
controller: _tabController, 
 
    เท่านี้เราก็สามารถจัดการกับ tab ผ่าน _tabController ได้ เหมือนตัวอย่างการกำหนดที่ปุ่ม
เมื่อกดที่ปุ่มก็ให้ไปที่ tab ที่ 4 
 
 _tabController.animateTo(3);
 
 
    เนื้อหาเกี่ยวกับการใช้งาน tab ก็มีประมาณนี้ สามารถนำไปประยุกต์ใช้งาน และทำความ
เข้าใจเพิ่มเติม ดูเกี่ยวกับคำสั่งการทำงานอื่นๆ ได้ที่ TabController


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



อ่านต่อที่บทความ









เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง











เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ