플러터:화면 전환(화면 쌓기, 하단 네비게이션 바): 두 판 사이의 차이
편집 요약 없음 |
잔글 →다른 프로젝트 |
||
| 112번째 줄: | 112번째 줄: | ||
기본 예제는 MaterialPageRoute로 충분하다. | 기본 예제는 MaterialPageRoute로 충분하다. | ||
= 기본 하단 네비게이션바 = | |||
<syntaxhighlight lang="dart"> | |||
import 'package:flutter/material.dart'; | |||
= | void main() => runApp(MyApp()); | ||
class MyApp extends StatelessWidget { | |||
@override | |||
Widget build(BuildContext context) { | |||
return MaterialApp( | |||
title: 'BottomNavigation Demo', | |||
debugShowCheckedModeBanner: false, | |||
home: HomePage(), | |||
); | |||
} | |||
} | |||
class HomePage extends StatefulWidget { | |||
@override | |||
State<HomePage> createState() => _HomePageState(); | |||
} | |||
class _HomePageState extends State<HomePage> { | |||
int _selectedIndex = 0; // 현재 선택된 탭 | |||
// 탭마다 보여줄 화면 | |||
static const List<Widget> _pages = <Widget>[ | |||
Center(child: Text('첫 번째 화면', style: TextStyle(fontSize: 24))), | |||
Center(child: Text('두 번째 화면', style: TextStyle(fontSize: 24))), | |||
Center(child: Text('세 번째 화면', style: TextStyle(fontSize: 24))), | |||
]; | |||
void _onItemTapped(int index) { | |||
setState(() { | |||
_selectedIndex = index; // 탭 선택 시 상태 변경 | |||
}); | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
return Scaffold( | |||
appBar: AppBar(title: Text('BottomNavigationBar Demo')), | |||
body: _pages[_selectedIndex], // 현재 선택된 화면 표시 | |||
bottomNavigationBar: BottomNavigationBar( | |||
currentIndex: _selectedIndex, | |||
onTap: _onItemTapped, // 탭 클릭 시 호출 | |||
items: const <BottomNavigationBarItem>[ | |||
BottomNavigationBarItem( | |||
icon: Icon(Icons.home), | |||
label: '홈', | |||
), | |||
BottomNavigationBarItem( | |||
icon: Icon(Icons.business), | |||
label: '비즈니스', | |||
), | |||
BottomNavigationBarItem( | |||
icon: Icon(Icons.school), | |||
label: '학교', | |||
), | |||
], | |||
), | |||
); | |||
} | |||
} | |||
</syntaxhighlight> | |||
= 이해를 위한 추가 설명 = | |||
{| class="wikitable" | |||
!요소 | |||
!설명 | |||
!비고 | |||
StatefulWidget | |||
하단 탭 선택 상태를 관리해야 하므로 HomePage를 StatefulWidget으로 정의 | |||
StatelessWidget이면 선택된 탭 정보를 저장할 수 없음 | |||
- | |||
_selectedIndex | |||
현재 선택된 탭의 인덱스를 저장하는 상태 변수 | |||
탭을 클릭하면 setState()로 값 변경 | |||
- | |||
_pages | |||
각 탭에 대응하는 화면 위젯 리스트 | |||
_selectedIndex를 이용해 화면 전환 | |||
- | |||
_onItemTapped | |||
탭 클릭 시 호출되는 함수 | |||
setState() 안에서 _selectedIndex 값을 바꾸어 화면 갱신 | |||
- | |||
BottomNavigationBar | |||
하단 네비게이션바 위젯 | |||
currentIndex: 선택된 탭 표시, onTap: 탭 클릭 시 동작 지정, items: 각 탭의 아이콘과 라벨 | |||
- | |||
currentIndex | |||
현재 선택된 탭을 표시 | |||
_selectedIndex와 연결 | |||
- | |||
onTap | |||
탭 클릭 이벤트 | |||
_onItemTapped 함수 연결 | |||
} | |||
|} | |||
== 의문 == | |||
=== StatelessWidget으로도 만들 수 없나? === | |||
탭 선택 상태를 저장할 방법이 없으므로 일반 StatelessWidget으로는 불가능하다. | |||
탭 상태를 유지하면서 화면 전환하려면 StatefulWidget을 사용해야 한다. | |||
=== BottomNavigationBarType 옵션은? === | |||
fixed: 모든 탭이 항상 같은 너비로 표시 | |||
shifting: 선택된 탭 강조, 배경색 변화 가능 | |||
기본값은 탭이 3개 이상이면 fixed, 3개 이하이면 shifting | |||
=== AppBar, Body, BottomNavigationBar 구조는 꼭 이렇게 해야 하나? === | |||
대부분의 경우 Scaffold 안에서 body와 bottomNavigationBar를 함께 사용한다. | |||
AppBar는 선택 사항이며 필요 없으면 생략 가능. | |||
2025년 11월 16일 (일) 15:46 판
- 플러터:개요
- 플러터:실행
- 플러터:개념 잡기
- 권한 사용
- 위젯
- 플러터:DB연결
- 플러터:Firebase(미완)
- 플러터:MySQL(미완)
- 디자인
- 플러터:배포
- 플러터:참고자료
- 플러터:위젯
- 플러터:라이브러리
개요
네이게이션을 통한 화면전환.
- Flutter 앱에서 화면을 이동하는 가장 기본적인 방식은 Navigator를 사용하는 것이다.
- Navigator는 “화면(stack)”을 관리하며, 새로운 페이지를 push하여 화면을 열고 pop하여 닫는다.
기본 화면 전환
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Navigator Demo',
debugShowCheckedModeBanner: false,
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
// StatelessWidget: 상태(state)를 가지지 않는 화면
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("첫 번째 화면"),
),
body: Center(
child: ElevatedButton(
child: Text("두 번째 화면으로 이동"),
onPressed: () {
// 화면 이동 (push)
Navigator.push(
context,
MaterialPageRoute(builder: (_) => SecondPage()),
);
},
),
),
);
}
}
class SecondPage extends StatelessWidget {
// 두 번째 화면도 상태를 가지지 않는 StatelessWidget
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("두 번째 화면"),
),
body: Center(
child: Text(
"여기는 두 번째 화면!",
style: TextStyle(fontSize: 24),
),
),
);
}
}
이해를 위한 추가 설명
| 요소 | 설명 | 비고 |
|---|---|---|
| 화면을 위에 올리기.
Navigator.push |
Navigator.push(
context,
MaterialPageRoute(builder: (_) => SecondPage()),
);
새로운 페이지를 스택 위에 ‘올려서’ 이동한다. MaterialPageRoute는 기본적인 화면 전환 애니메이션을 제공한다. |
마테리얼 디자인 규칙에 따라 뒤로가기가 가능하면 자동으로 뒤로가기 버튼이 생긴다. |
| 뒤로 가기
Navigator.pop |
Navigator.pop(context)
현재 페이지를 스택에서 제거(pop)하여 이전 화면으로 돌아간다. |
의문
왜 push()는 context가 필요한가?
Navigator는 위젯 트리 안에 존재하는 “Navigator State”를 찾아야 하는데, 이를 위해 현재 위젯의 BuildContext가 필요하다.
BuildContext는 “현재 위젯이 트리에서 어디 위치하는지”를 나타내는 정보다.
MaterialPageRoute 말고 다른 것도 있나?
있다.
- CupertinoPageRoute (iOS 스타일 전환)
- PageRouteBuilder (전환 애니메이션 직접 커스텀)
- go_router, auto_route 같은 라우팅 라이브러리
기본 예제는 MaterialPageRoute로 충분하다.
기본 하단 네비게이션바
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'BottomNavigation Demo',
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _selectedIndex = 0; // 현재 선택된 탭
// 탭마다 보여줄 화면
static const List<Widget> _pages = <Widget>[
Center(child: Text('첫 번째 화면', style: TextStyle(fontSize: 24))),
Center(child: Text('두 번째 화면', style: TextStyle(fontSize: 24))),
Center(child: Text('세 번째 화면', style: TextStyle(fontSize: 24))),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index; // 탭 선택 시 상태 변경
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('BottomNavigationBar Demo')),
body: _pages[_selectedIndex], // 현재 선택된 화면 표시
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped, // 탭 클릭 시 호출
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '홈',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: '비즈니스',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: '학교',
),
],
),
);
}
}
이해를 위한 추가 설명
| 요소 | 설명 | 비고
StatefulWidget 하단 탭 선택 상태를 관리해야 하므로 HomePage를 StatefulWidget으로 정의 StatelessWidget이면 선택된 탭 정보를 저장할 수 없음 - _selectedIndex 현재 선택된 탭의 인덱스를 저장하는 상태 변수 탭을 클릭하면 setState()로 값 변경 - _pages 각 탭에 대응하는 화면 위젯 리스트 _selectedIndex를 이용해 화면 전환 - _onItemTapped 탭 클릭 시 호출되는 함수 setState() 안에서 _selectedIndex 값을 바꾸어 화면 갱신 - BottomNavigationBar 하단 네비게이션바 위젯 currentIndex: 선택된 탭 표시, onTap: 탭 클릭 시 동작 지정, items: 각 탭의 아이콘과 라벨 - currentIndex 현재 선택된 탭을 표시 _selectedIndex와 연결 - onTap 탭 클릭 이벤트 _onItemTapped 함수 연결 } |
|---|
의문
StatelessWidget으로도 만들 수 없나?
탭 선택 상태를 저장할 방법이 없으므로 일반 StatelessWidget으로는 불가능하다. 탭 상태를 유지하면서 화면 전환하려면 StatefulWidget을 사용해야 한다.
BottomNavigationBarType 옵션은?
fixed: 모든 탭이 항상 같은 너비로 표시
shifting: 선택된 탭 강조, 배경색 변화 가능
기본값은 탭이 3개 이상이면 fixed, 3개 이하이면 shifting
AppBar, Body, BottomNavigationBar 구조는 꼭 이렇게 해야 하나?
대부분의 경우 Scaffold 안에서 body와 bottomNavigationBar를 함께 사용한다. AppBar는 선택 사항이며 필요 없으면 생략 가능.