플러터:화면 전환(화면 쌓기, 하단 네비게이션 바): 두 판 사이의 차이
보이기
잔글 →다른 프로젝트 |
잔글 Sam님이 플러터:화면 전환(화면 쌓기, 하단 네비게이션 바)(화면 쌓기, 하단 네비게이션 바) 문서를 플러터:화면 전환(화면 쌓기, 하단 네비게이션 바) 문서로 이동하면서 넘겨주기를 덮어썼습니다 |
||
| (같은 사용자의 중간 판 6개는 보이지 않습니다) | |||
| 4번째 줄: | 4번째 줄: | ||
네이게이션을 통한 화면전환. | 네이게이션을 통한 화면전환. | ||
기본적으로 네비게이션바로 구조를 잡고, 네비게이터로 상세 화면을 다루는 형식을 많이 쓴다. | |||
= 기본 화면 전환(Navigator) = | |||
* Flutter 앱에서 화면을 이동하는 가장 기본적인 방식은 Navigator를 사용하는 것이다. | * Flutter 앱에서 화면을 이동하는 가장 기본적인 방식은 Navigator를 사용하는 것이다. | ||
* Navigator는 “화면(stack)”을 관리하며, 새로운 페이지를 push하여 화면을 열고 pop하여 닫는다. | * Navigator는 “화면(stack)”을 관리하며, 새로운 페이지를 push하여 화면을 열고 pop하여 닫는다. | ||
<syntaxhighlight lang="dart">import 'package:flutter/material.dart'; | <syntaxhighlight lang="dart">import 'package:flutter/material.dart'; | ||
| 39번째 줄: | 40번째 줄: | ||
// 화면 이동 (push) | // 화면 이동 (push) | ||
Navigator.push( | Navigator.push( | ||
context, | context, // 현재 위젯의 위치가 어디인지.(어디 위에 화면을 올릴 것인지.) | ||
MaterialPageRoute(builder: (_) => SecondPage()), | MaterialPageRoute(builder: (_) => SecondPage()), | ||
); | ); | ||
| 65번째 줄: | 66번째 줄: | ||
); | ); | ||
} | } | ||
} | }</syntaxhighlight> | ||
</syntaxhighlight> | |||
== 이해를 위한 추가 설명 == | == 이해를 위한 추가 설명 == | ||
| 77번째 줄: | 77번째 줄: | ||
|화면을 위에 올리기. | |화면을 위에 올리기. | ||
Navigator.push | Navigator.push | ||
|<syntaxhighlight lang="dart"> | |<syntaxhighlight lang="dart">Navigator.push( | ||
Navigator.push( | |||
context, | context, | ||
MaterialPageRoute(builder: (_) => SecondPage()), | MaterialPageRoute(builder: (_) => SecondPage()), | ||
); | );</syntaxhighlight> | ||
</syntaxhighlight> | |||
새로운 페이지를 스택 위에 ‘올려서’ 이동한다. | 새로운 페이지를 스택 위에 ‘올려서’ 이동한다. | ||
| 88번째 줄: | 86번째 줄: | ||
MaterialPageRoute는 기본적인 화면 전환 애니메이션을 제공한다. | MaterialPageRoute는 기본적인 화면 전환 애니메이션을 제공한다. | ||
|마테리얼 디자인 규칙에 따라 뒤로가기가 가능하면 자동으로 뒤로가기 버튼이 생긴다. | |마테리얼 디자인 규칙에 따라 뒤로가기가 가능하면 자동으로 뒤로가기 버튼이 생긴다. | ||
<code>_</code>는 '인자를 받긴 해야 하지만, 나는 쓰지 않겠다'라는 의미의 Dart 관례적인 이름.(원랜 BuildContext context가 들어감.) | |||
|- | |- | ||
|뒤로 가기 | |뒤로 가기 | ||
| 94번째 줄: | 93번째 줄: | ||
현재 페이지를 스택에서 제거(pop)하여 이전 화면으로 돌아간다. | 현재 페이지를 스택에서 제거(pop)하여 이전 화면으로 돌아간다. | ||
| | |위 코드엔 없지만, 특정 함수에서 진행하면 창이 닫힌다. | ||
|} | |} | ||
=== 결론 === | |||
스택을 쌓아 화면이 바뀐다. | |||
== 의문 == | == 의문 == | ||
| 110번째 줄: | 112번째 줄: | ||
* PageRouteBuilder (전환 애니메이션 직접 커스텀) | * PageRouteBuilder (전환 애니메이션 직접 커스텀) | ||
* go_router, auto_route 같은 라우팅 라이브러리 | * go_router, auto_route 같은 라우팅 라이브러리 | ||
= 기본 하단 네비게이션 바 = | |||
<syntaxhighlight lang="dart">import 'package:flutter/material.dart'; | |||
= 기본 하단 | |||
<syntaxhighlight lang="dart"> | |||
import 'package:flutter/material.dart'; | |||
void main() => runApp(MyApp()); | void main() => runApp(MyApp()); | ||
class MyApp extends StatelessWidget { | class MyApp extends StatelessWidget { | ||
@override | @override | ||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||
return MaterialApp( | return MaterialApp( | ||
title: 'BottomNavigation Demo', | title: 'BottomNavigation Demo', | ||
debugShowCheckedModeBanner: false, | debugShowCheckedModeBanner: false, | ||
home: HomePage(), | home: HomePage(), | ||
); | ); | ||
} | } | ||
} | } | ||
class HomePage extends StatefulWidget { | class HomePage extends StatefulWidget { | ||
@override | @override | ||
State<HomePage> createState() => _HomePageState(); | State<HomePage> createState() => _HomePageState(); | ||
} | } | ||
class _HomePageState extends State<HomePage> { | class _HomePageState extends State<HomePage> { | ||
int _selectedIndex = 0; // 현재 선택된 탭 | int _selectedIndex = 0; // 현재 선택된 탭 | ||
// 탭마다 보여줄 화면 | // 탭마다 보여줄 화면 | ||
static const List<Widget> _pages = <Widget>[ | static const List<Widget> _pages = <Widget>[ // static은 클래스 변수임을 의미미(인스턴스가 생길 때마다 새로 만들지는 않겠다.) | ||
Center(child: Text('첫 번째 화면', style: TextStyle(fontSize: 24))), | Center( | ||
Center(child: Text('두 번째 화면', style: TextStyle(fontSize: 24))), | child: Text( | ||
Center(child: Text('세 번째 화면', style: TextStyle(fontSize: 24))), | '첫 번째 화면', | ||
]; | style: TextStyle(fontSize: 24), | ||
), | |||
), | |||
Center( | |||
child: Text( | |||
'두 번째 화면', | |||
style: TextStyle(fontSize: 24), | |||
), | |||
), | |||
Center( | |||
child: Text( | |||
'세 번째 화면', | |||
style: TextStyle(fontSize: 24), | |||
), | |||
), | |||
]; | |||
void _onItemTapped(int index) { | void _onItemTapped(int index) { | ||
setState(() { | setState(() { | ||
_selectedIndex = index; // 탭 선택 시 상태 변경 | _selectedIndex = index; // 탭 선택 시 상태 변경 | ||
}); | }); | ||
} | } | ||
@override | @override | ||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||
return Scaffold( | return Scaffold( | ||
appBar: AppBar(title: Text('BottomNavigationBar Demo')), | appBar: AppBar( | ||
body: _pages[_selectedIndex], // 현재 선택된 화면 표시 | title: Text('BottomNavigationBar Demo'), | ||
bottomNavigationBar: BottomNavigationBar( | ), | ||
currentIndex: _selectedIndex, | body: _pages[_selectedIndex], // 현재 선택된 화면 표시 | ||
onTap: _onItemTapped, // 탭 클릭 시 호출 | bottomNavigationBar: BottomNavigationBar( | ||
items: const <BottomNavigationBarItem>[ | currentIndex: _selectedIndex, | ||
BottomNavigationBarItem( | onTap: _onItemTapped, // 탭 클릭 시 호출 | ||
icon: Icon(Icons.home), | items: const <BottomNavigationBarItem>[ | ||
label: '홈', | BottomNavigationBarItem( | ||
), | icon: Icon(Icons.home), | ||
BottomNavigationBarItem( | label: '홈', | ||
icon: Icon(Icons.business), | ), | ||
label: '비즈니스', | BottomNavigationBarItem( | ||
), | icon: Icon(Icons.business), | ||
BottomNavigationBarItem( | label: '비즈니스', | ||
icon: Icon(Icons.school), | ), | ||
label: '학교', | BottomNavigationBarItem( | ||
), | icon: Icon(Icons.school), | ||
], | label: '학교', | ||
), | ), | ||
); | ], | ||
} | ), | ||
} | ); | ||
</syntaxhighlight> | } | ||
}</syntaxhighlight> | |||
= 이해를 위한 추가 설명 = | = 이해를 위한 추가 설명 = | ||
| 184번째 줄: | 199번째 줄: | ||
!비고 | !비고 | ||
|- | |||
|_onItemTapped | |||
|탭 클릭 시 호출되는 함수. | |||
자동으로 Index가 입력된다. | |||
| | |||
|- | |||
|BottomNavigationBarType | |||
|옵션은? | |||
* fixed: 모든 탭이 항상 같은 너비로 표시 | |||
* shifting: 선택된 탭 강조, 배경색 변화 가능 | |||
- | |||
_onItemTapped | 기본값은 탭이 4개 이하면 fixed, 4개 이상이면 shifting | ||
탭 클릭 시 호출되는 함수 | |||
기본값은 아래 옵션으로 바꾸어 지정 가능. | |||
- | |||
type: BottomNavigationBarType.fixed, // 고정형 | |||
|shifting이면 각 탭에 색을 넣어주어야 한다. | |||
backgroundColor: Colors.blue, 형태로. | |||
|} | |} | ||
| 218번째 줄: | 223번째 줄: | ||
=== StatelessWidget으로도 만들 수 없나? === | === StatelessWidget으로도 만들 수 없나? === | ||
탭 선택 상태를 저장할 방법이 없으므로 일반 StatelessWidget으로는 불가능하다. | 탭 선택 상태를 저장할 방법이 없으므로 일반 StatelessWidget으로는 불가능하다. 탭 상태를 유지하면서 화면 전환하려면 StatefulWidget을 사용해야 한다. | ||
탭 상태를 유지하면서 화면 전환하려면 StatefulWidget을 사용해야 한다 | |||
2026년 1월 7일 (수) 01:50 기준 최신판
- 플러터:개요
- 플러터:실행
- 플러터:개념 잡기
- 권한 사용
- 위젯
- 플러터: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)하여 이전 화면으로 돌아간다. |
위 코드엔 없지만, 특정 함수에서 진행하면 창이 닫힌다. |
스택을 쌓아 화면이 바뀐다.
Navigator는 위젯 트리 안에 존재하는 “Navigator State”를 찾아야 하는데, 이를 위해 현재 위젯의 BuildContext가 필요하다.
BuildContext는 “현재 위젯이 트리에서 어디 위치하는지”를 나타내는 정보다.
있다.
- CupertinoPageRoute (iOS 스타일 전환)
- PageRouteBuilder (전환 애니메이션 직접 커스텀)
- go_router, auto_route 같은 라우팅 라이브러리
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>[ // static은 클래스 변수임을 의미미(인스턴스가 생길 때마다 새로 만들지는 않겠다.)
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: '학교',
),
],
),
);
}
}
| 요소 | 설명 | 비고 |
|---|---|---|
| _onItemTapped | 탭 클릭 시 호출되는 함수.
자동으로 Index가 입력된다. |
|
| BottomNavigationBarType | 옵션은?
기본값은 탭이 4개 이하면 fixed, 4개 이상이면 shifting 기본값은 아래 옵션으로 바꾸어 지정 가능. type: BottomNavigationBarType.fixed, // 고정형 |
shifting이면 각 탭에 색을 넣어주어야 한다.
backgroundColor: Colors.blue, 형태로. |
탭 선택 상태를 저장할 방법이 없으므로 일반 StatelessWidget으로는 불가능하다. 탭 상태를 유지하면서 화면 전환하려면 StatefulWidget을 사용해야 한다.