일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 |
Tags
- Linux 디렉터리 구조
- Linux 디렉터리 역할
- ec2 ssh unprotected private key file
- javascript 정렬
- EC2 oh my zsh
- EC2 HTTP 호스팅
- EC2 zsh
- EC2 Apache2
- linux foreground
- Linux pwd
- Linux 파일 관리 명령어
- Linux ls
- Linux 디렉터리 명령어
- arbitrum sepolia eth
- Linux oh my zsh
- Linux rmdir
- HTTP Web Server
- 서버의 서비스 방식
- Navigation Pattern
- linux background
- Linux apt
- Linux mkdir
- 아비트럼 새폴리아 이더 받는법
- AWS EC2 서버 만들기
- Linux cat
- Linux apt-get
- javascript scope
- Linux cd
- UNPROTECTED PRIVATE KEY FILE
- Logback
Archives
- Today
- Total
HyunJun 기술 블로그
Navigation Pattern, Tab Navigation 본문
728x90
반응형
Tab Navigation
이전 글 (2023.07.11 - [Dart/Flutter] - Navigation Pattern, Navigator, Named Routes, Parameters)에서 플러터에는 어떠한 Navigation Pattern이 있는지와 플러터의 가장 기본적인 내비게이션 패턴인 스택 기반 내비게이션(Stack-based Navigation)을 이용한 Navigator 사용법 등과 Named Routes 등을 알아보았다. 그렇다면 이번 시간에는 Tab Navigation에 대해서 알아보려고 한다.
Tab Navigation이란 여러 개의 탭을 사용하여 다양한 기능이나 섹션을 표현하고, 사용자가 각 탭을 선택(클릭) 하여 해당 컨텐츠를 보거나 해당 기능으로 이동할 수 있는 내비게이션 패턴을 말한다. Tab Navigation에는 크게 4가지 정도의 패턴이 있다.
- BottomNavigationBar: 하단에 위치하여 여러 개의 탭을 아이콘 또는 라벨과 함께 보여주고, 사용자가 탭을 선택하여 해당 컨텐츠를 보여주는데 사용되는 방식이다.
- TabBar와 TabBarView: 상단에 위치하여 탭 바를 구현하는 방식으로, TabBar는 탭 바에 표시될 탭들의 목록을 표시하고, TabBarView는 선택된 탭에 해당하는 컨텐츠를 표시한다.
- CupertinoTabBar와 CupertinoTabScaffold: iOS 스타일의 탭 바를 구현하는 방식으로, CupertinoTabBar는 iOS의 하단에 위치하는 탭 바를 표시하고, CupertinoTabScaffold는 iOS의 기본 앱 구성을 따르는 스캐폴드(Scaffold)를 제공한다.
- Custom Tab Bar: 개발자의 요구에 따라 커스텀 한 탭 바를 구현하는 방식으로, 기본적인 탭 바의 디자인과 기능을 커스텀 하여 원하는 스타일로 탭 바를 구성할 수 있다.
탭 내비게이션은 앱의 다양한 기능과 섹션을 사용자에게 쉽게 제공하고, 각 탭을 선택하여 빠르게 화면 전환을 할 수 있도록 해주는 유용한 패턴이다. 따라서 위에서 언급한 4가지 방식은 모두 탭 내비게이션에 속하며, 앱의 구조와 디자인에 맞게 선택하여 사용할 수 있다.
1) BottomNavigationBar
BottomNavigationBar에 item들을 정의하고 해당 item 클릭 시 인덱스를 받아와 body에 위젯을 변경하는 형태이다.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyBottomNavigationBarApp(),
);
}
}
class MyBottomNavigationBarApp extends StatefulWidget {
@override
_MyBottomNavigationBarAppState createState() => _MyBottomNavigationBarAppState();
}
class _MyBottomNavigationBarAppState extends State<MyBottomNavigationBarApp> {
int _currentIndex = 0;
// 각 탭에 해당하는 화면들을 리스트로 정의
List<Widget> _screens = [
HomeScreen(),
SearchScreen(),
FavoritesScreen(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bottom Navigation Bar Example'),
),
// 현재 선택된 탭에 해당하는 화면을 표시하는 바디 부분
body: _screens[_currentIndex],
// 하단에 탭 네비게이션 바를 생성
bottomNavigationBar: BottomNavigationBar(
// 현재 선택된 탭의 인덱스를 추적
currentIndex: _currentIndex,
// 탭을 선택했을 때 실행될 콜백 함수
onTap: (index) {
setState(() {
// 선택한 탭의 인덱스로 현재 선택된 탭을 변경
_currentIndex = index;
});
},
// 각 탭의 아이템들 정의
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite),
label: 'Favorites',
),
],
),
);
}
}
// 각 탭에 해당하는 컨텐츠 위젯들
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Home Screen', style: TextStyle(fontSize: 24)),
);
}
}
class SearchScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Search Screen', style: TextStyle(fontSize: 24)),
);
}
}
class FavoritesScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Favorites Screen', style: TextStyle(fontSize: 24)),
);
}
}
2) TabBar
AppBar 위치에 TabBar의 Tab들을 등록하여 클릭 시 화면전환이 되게 구현할 수 있다.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyTabBarApp(),
);
}
}
class MyTabBarApp extends StatefulWidget {
@override
_MyTabBarAppState createState() => _MyTabBarAppState();
}
class _MyTabBarAppState extends State<MyTabBarApp> with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
// TabController를 초기화하고 탭의 수를 설정
_tabController = TabController(length: 3, vsync: this);
}
@override
void dispose() {
// TabController를 dispose
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Tab Bar Example'),
bottom: TabBar(
// TabBar와 TabBarView를 연결하기 위해 TabController를 설정
controller: _tabController,
// 탭 바에 표시될 탭들의 목록
tabs: [
Tab(icon: Icon(Icons.home), text: 'Home'),
Tab(icon: Icon(Icons.search), text: 'Search'),
Tab(icon: Icon(Icons.favorite), text: 'Favorites'),
],
),
),
// 현재 선택된 탭에 해당하는 컨텐츠를 표시하는 바디 부분
body: TabBarView(
// TabBar와 TabBarView를 연결하기 위해 TabController를 설정
controller: _tabController,
// 각 탭에 해당하는 컨텐츠 위젯들 정의
children: [
HomeScreen(),
SearchScreen(),
FavoritesScreen(),
],
),
);
}
}
// 각 탭에 해당하는 컨텐츠 위젯들
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Home Screen', style: TextStyle(fontSize: 24)),
);
}
}
class SearchScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Search Screen', style: TextStyle(fontSize: 24)),
);
}
}
class FavoritesScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('Favorites Screen', style: TextStyle(fontSize: 24)),
);
}
}
3) CupertinoTabBar
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyCupertinoTabBarApp(),
);
}
}
class MyCupertinoTabBarApp extends StatefulWidget {
@override
_MyCupertinoTabBarAppState createState() => _MyCupertinoTabBarAppState();
}
class _MyCupertinoTabBarAppState extends State<MyCupertinoTabBarApp> {
int _currentIndex = 0;
// 각 탭에 해당하는 화면들을 리스트로 정의
List<Widget> _screens = [
HomeScreen(),
SearchScreen(),
FavoritesScreen(),
];
@override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
// 현재 선택된 탭의 인덱스를 추적
currentIndex: _currentIndex,
// 탭을 선택했을 때 실행될 콜백 함수
onTap: (index) {
setState(() {
// 선택한 탭의 인덱스로 현재 선택된 탭을 변경
_currentIndex = index;
});
},
// 각 탭의 아이템들 정의
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.heart),
label: 'Favorites',
),
],
),
tabBuilder: (context, index) {
// 현재 선택된 탭에 해당하는 컨텐츠를 표시
return _screens[index];
},
);
}
}
// 각 탭에 해당하는 컨텐츠 위젯들
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Home'),
),
child: Center(
child: Text('Home Screen', style: TextStyle(fontSize: 24)),
),
);
}
}
class SearchScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Search'),
),
child: Center(
child: Text('Search Screen', style: TextStyle(fontSize: 24)),
),
);
}
}
class FavoritesScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Favorites'),
),
child: Center(
child: Text('Favorites Screen', style: TextStyle(fontSize: 24)),
),
);
}
}
4) Custom Tab Bar
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyCustomTabBarApp(),
);
}
}
class MyCustomTabBarApp extends StatefulWidget {
@override
_MyCustomTabBarAppState createState() => _MyCustomTabBarAppState();
}
class _MyCustomTabBarAppState extends State<MyCustomTabBarApp> with TickerProviderStateMixin {
int _currentIndex = 0;
late AnimationController _controller;
// 각 탭에 해당하는 컨텐츠 위젯들을 리스트로 정의
List<Widget> _screens = [
HomeScreen(),
SearchScreen(),
FavoritesScreen(),
];
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
_controller.repeat(); // 애니메이션 반복
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Custom Tab Bar Example'),
),
// 현재 선택된 탭에 해당하는 컨텐츠를 표시하는 바디 부분
body: _screens[_currentIndex],
// 커스텀 탭 바
bottomNavigationBar: Container(
height: 80,
padding: EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.vertical(top: Radius.circular(16.0)),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 4,
offset: Offset(0, -2),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
_changeTab(0);
},
child: TabItem(text: 'Home', icon: Icons.home, isSelected: _currentIndex == 0, controller: _controller),
),
GestureDetector(
onTap: () {
_changeTab(1);
},
child: TabItem(text: 'Search', icon: Icons.search, isSelected: _currentIndex == 1, controller: _controller),
),
GestureDetector(
onTap: () {
_changeTab(2);
},
child: TabItem(text: 'Favorites', icon: Icons.favorite, isSelected: _currentIndex == 2, controller: _controller),
),
],
),
),
);
}
void _changeTab(int index) {
setState(() {
_currentIndex = index;
});
}
}
// 커스텀 탭 아이템
class TabItem extends StatelessWidget {
final String text;
final IconData icon;
final bool isSelected;
final AnimationController controller;
TabItem({required this.text, required this.icon, required this.isSelected, required this.controller});
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RotationTransition(
turns: controller,
child: Icon(
icon,
color: isSelected ? Colors.white : Colors.white60,
size: 28,
),
),
SizedBox(height: 8),
Text(
text,
style: TextStyle(
color: isSelected ? Colors.white : Colors.white60,
fontSize: 14,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
),
],
);
}
}
// 각 탭에 해당하는 컨텐츠 위젯들
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text('Home Screen', style: TextStyle(fontSize: 24)),
),
);
}
}
class SearchScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text('Search Screen', style: TextStyle(fontSize: 24)),
),
);
}
}
class FavoritesScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text('Favorites Screen', style: TextStyle(fontSize: 24)),
),
);
}
}
728x90
반응형
Comments