นำทาง Flutter ด้วย TabBar กันเถอะ
มาต่อกับชาเลนจ์ จากเด็กจบใหม่ที่ต้องติดบ้านเพราะโควิดสู่นักพัฒนา Flutter #4
บทความต่อจาก
Contents
- TabBar (Top)
- TabBar (Downstairs)
- AppBar
TabBar (Top)
เป็นปุ่มที่คอยนำทางไปหน้าต่างๆโดยเปลี่ยนแค่ส่วน body (ถ้านึกไม่ออกให้เปิดแอปไลน์แล้วดูปุ่มข้างล่างสุดจะเจอ TabBar) ซึ่ง TabBar สามารถอยู่ได้ทั้งข้างบนและข้างล่างนะครับ
เริ่มแรกให้เราเตรียมของที่จะวางไว้ที่ TabBar ก่อน
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}const List<Choice> choices = const <Choice>[
const Choice(title: 'Car', icon: Icons.directions_car),
const Choice(title: 'Bicycle', icon: Icons.directions_bike),
const Choice(title: 'Boat', icon: Icons.directions_boat),
const Choice(title: 'Bus', icon: Icons.directions_bus),
const Choice(title: 'Train', icon: Icons.directions_railway),
const Choice(title: 'Walk', icon: Icons.directions_walk),
];
2.ในการสร้าง Tabbar สิ่งที่ต้องประกาศคือ TabControlle
เป็นตัวกำหนดจำนวน tab ที่มีอยู่ทั้งหมดโดย child จะต้องมีจำนวนเท่ากับ length
เท่านั้นเพื่อที่จะสร้าง tab ไม่ขาดไม่เกิน
DefaultTabController(
// The number of tabs / content sections to display.
length: choices.length, // int
child: // Complete this code in the next step.
);
3.สร้าง tabs หรือก็คือใส่ชื่ออ้างอิงในแต่ละ tabs
DefaultTabController(
length: choices.length,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
// tabs: [
// Tab(icon: Icon(Icons.directions_car)),
// Tab(icon: Icon(Icons.directions_transit)),
// Tab(icon: Icon(Icons.directions_bike)),
// ],
tabs: choices.map((Choice choice) {
return Tab(
text: choice.title,
icon: Icon(choice.icon),
);
}).toList(),
),
),
),
);
4. ใส่เนื้อหาในแต่ละ tabs ด้วย TabBarView
TabBarView(
// children: [
// Icon(Icons.directions_car),
// Icon(Icons.directions_transit),
// Icon(Icons.directions_bike),
// ],
children: choices.map((Choice choice) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(choice.icon, size: 128.0),
Text(choice.title),
],
),
);
}).toList(),
);
เพิ่มเติม
initialIndex
เป็นการกำหนดว่าเมื่อเข้ามาครั้งแรกจะโชว์ tab ที่เท่าไร
initialIndex: 3,
isScrollable
ถ้าเกิดว่าเราใส่ tabs เยอะไปจะทำให้ tab ถูกบีบจนไม่สวยหรือหน้าแสดงผลไม่ได้
ผู้อ่านสามารถทำให้ tabs scroll ได้นะครับ โดยผมจะทำการ custom tab ก่อนเผื่อให้ tabs มันเกินหน้าก่อน แล้วใส่ true ใน isScrollable ก็จะสามารถเลื่อนได้แล้วครับ
isScrollable: true,
tabs: choices.map((Choice choice) {
return Tab(
child: Row(
children: <Widget>[
Icon(choice.icon),
Container(
margin: EdgeInsets.only(left: 8),
child: Text(choice.title),
)
],
),
);
}).toList(),
unselectedLabelColor
ใส่สีให้ tabs ที่ user ไม่ได้เลือกอยู่ครับ
unselectedLabelColor: Colors.black
indicatorWeight
คือเพิ่มขนาด bar ที่เลือกครับ
indicatorWeight: 10
indicatorColor
คือเปลียนสี bar ที่เลือกครับ
indicatorColor: Colors.yellow
labelColor
labelColor: Colors.redAccent
onTap
เป็นตัวดักว่า user กดปุ่มไหนครับ
onTap: (index) {
print("index: ${index}");
}
TabBar (Downstairs)
โค้ดเหมือน TabBar (Top) ทุกอย่างเลยครับแค่วางไว้ที่ bottomNavigationBar
SafeArea
จะทำให้ tabs เราไม่อยู่ต่ำมากไปใน iphone รุ่นใหม่ๆครับ
AppBar
AppBar ไม่ได้ใส่ได้เพียง title เท่านั้นแต่ยังสามารถใส่ปุ่มและ dropdown menu ได้ด้วย
เริ่มแรกให้เราเตรียมของที่จะวางไว้ที่ dropdown menu ซึ่งเป็นก้อนเดียวกับที่ผมใช้กับ TabBar
class Choice {
const Choice({this.title, this.icon}); final String title;
final IconData icon;
}const List<Choice> choices = const <Choice>[
const Choice(title: 'Car', icon: Icons.directions_car),
const Choice(title: 'Bicycle', icon: Icons.directions_bike),
const Choice(title: 'Boat', icon: Icons.directions_boat),
const Choice(title: 'Bus', icon: Icons.directions_bus),
const Choice(title: 'Train', icon: Icons.directions_railway),
const Choice(title: 'Walk', icon: Icons.directions_walk),
];
ผมจะสือบทอด StatefulWidget เพราะว่ามันจะตรวจจับว่าผู้ใช้คลิกแล้วไปเปลี่ยนข้อมูลนั้นเอง โดย BasicAppBarSample จะเป็น state
// This app is a stateful, it tracks the user's current choice.
class BasicAppBarSample extends StatefulWidget {
@override
_BasicAppBarSampleState createState() => _BasicAppBarSampleState();
}
หลังจากนั้นก็สร้าง _BasicAppBarSampleState เพื่อตรวจจับว่ามีการ setState หรือไม่ถ้ามีมันจะไปบอกให้ BasicAppBarSample ทำการ createState ใหม่ครับ
class _BasicAppBarSampleState extends State<BasicAppBarSample> {
Choice _selectedChoice = choices[0]; // The app's "state".
void _select(Choice choice) {
// Causes the app to rebuild with the new _selectedChoice.
setState(() {
_selectedChoice = choice;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
// centerTitle: true,
title: const Text('Basic AppBar'),
actions: <Widget>[
// action button
IconButton(
icon: Icon(choices[0].icon),
onPressed: () {
_select(choices[0]);
},
),
// action button
IconButton(
icon: Icon(choices[1].icon),
onPressed: () {
_select(choices[1]);
},
),
// overflow menu
PopupMenuButton<Choice>(
onSelected: _select,
itemBuilder: (BuildContext context) {
return choices.skip(2).map((Choice choice) {
return PopupMenuItem<Choice>(
value: choice,
child: Text(choice.title),
);
}).toList();
},
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: ChoiceCard(choice: _selectedChoice),
),
),
);
}
}
จบท้ายด้วยการส่งค่าที่ผู้ใช้เลือกส่งไปยัง ChoiceCard
class ChoiceCard extends StatelessWidget {
const ChoiceCard({Key key, this.choice}) : super(key: key);
final Choice choice;
@override
Widget build(BuildContext context) {
final TextStyle textStyle = Theme.of(context).textTheme.display1;
return Card(
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(choice.icon, size: 128.0, color: textStyle.color),
Text(choice.title, style: textStyle),
],
),
),
);
}
}
Keys
ตามที่ผมเข้าใจ keys จะเป็นค่า unique ที่มีไว้เพื่อควบคุม widgets
ยกตัวอย่างเช่นมี widget A,B เรียงกันอยู่ A อยู่ตำแหน่งที่ 1 B อยู่ตำแหน่งที่ 2
จู่ๆ widget B ถูกลากไปอยู่ตำแหน่งที่ 1 เมื่อผู้ใช้คลิก widget ที่ตำแหน่งที่ 1 แอปก็จะรู้ได้ว่า widget ที่ตำแหน่งที่ 1 ไม่ใช่ A แต่เป็น B แล้วและเมื่อ widgets ถูกสร้างขึ้นใหม่ก็จะมี keys เป็นของตัวเอง
โค้ดทั้งหมดครับ
Property เพิ่มเติม
centerTitle
ตามชื่อครับ ชื่ออยู่ตรงกลาง
centerTitle: true
elevation
เป็นการใส่เงาให้ Appbar ครับ
titleSpacing
เป็นการขยับ title ตามค่าที่เรากำหนดครับ แต่ถ้าชื่อยาวจนแสดงผลไม่พอจะแสดง …
textTheme
เป็นการใส่ธีมให้ title ครับ
textTheme: TextTheme(title: TextStyle(color: Colors.red, fontSize: 20))
iconTheme
เป็นการใส่ธีมให้ icon ครับ
iconTheme: IconThemeData(color: Colors.red, size: 50)
iconSize
เพิ่มขนาดให้ icon
iconSize: 40
highlightColor
เปลี่ยนสีการคลิกปุ่มครับ *พอดีไม่สามารถแคปได้
highlightColor: Colors.red
splashColor
เปลี่ยนสีเวลาผู้ใช้คลิกค้างที่ปุ่มครับ *พอดีไม่สามารถแคปได้
splashColor: Colors.cyan
วันนี้ขอจบบทความเท่านี้นะครับ ถ้ามีอะไรติชมเขียนมาได้เลยนะครับ ผมจะได้เอาไปปรับปรุงในบทความต่อไป ขอบคุณที่อ่านจนจบครับ