일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- MVVM
- MS-SQL
- spring boot
- 애니메이션
- 깃허브
- 마우이
- typescript
- 플러터
- 리엑트
- 바인딩
- AnimationController
- 파이어베이스
- JavaScript
- listview
- page
- Flutter
- 오류
- Firebase
- React JS
- MSSQL
- 함수
- db
- Maui
- Binding
- Animation
- 자바스크립트
- .NET
- 닷넷
- GitHub
- HTML
Archives
- Today
- Total
개발노트
73. [Flutter] GoRoute, Stack, OffStage 조합으로 bottomNavigationBar 화면 만들기 본문
앱 개발/Flutter
73. [Flutter] GoRoute, Stack, OffStage 조합으로 bottomNavigationBar 화면 만들기
mroh1226 2024. 3. 7. 15:47반응형
bottomNavigationBar을 만들 때 GoRoute, Stack, OffStage 조합을 사용하는 이유는 다음과 같습니다.
- GoRoute: GoRoute는 일반적으로 네비게이션 기능을 제공하는 라우팅 패키지로 이를 사용하여 앱의 다양한 화면 간의 이동을 관리할 수 있습니다. 특히, Web에서의 동작을 path와 같은 URL로 처리할 수 있습니다.
- Stack: Stack 위젯은 위에서 아래로 겹쳐진 위젯을 나타냅니다. 여러 화면을 겹쳐서 표시하고, 사용자가 뒤로가기 버튼을 눌렀을 때 이전 화면으로 돌아가게 합니다. 이것은 사용자 경험을 향상시키고, 앱의 내비게이션을 관리하는 데 도움이 됩니다.
- OffStage: OffStage 위젯은 화면에서 숨겨진 상태로 위젯을 유지합니다. 이를 통해 앱의 여러 화면을 미리 로드하고, 사용자가 해당 화면으로 이동할 때까지 렌더링하지 않을 수 있습니다. 이는 성능을 향상시키고, 사용자 경험을 개선하는 데 도움이 됩니다.
즉, Stack에 여러개의 화면을 미리 렌더링하여 시간을 단축 시키고, Offstage를 통해 화면의 Visiblity를 이용하여 사용중인 화면을 dispose 하지않고 다른 화면을 보여줍니다. 이를 GoRoute의 Parameter로 주고받으며 관리합니다.
router.dart (GoRoute)
final routeProvider = Provider((ref) {
return GoRouter(
//initialLocation: 시작 URL 따로 위젯을 return 안해도 알아서 작동함 맨 앞에"/"는 필수
initialLocation: "/home",
routes: [
GoRoute(
path: "/:tab(home|search|receipt|profile)",
name: NavigationScreen.routeName,
builder: (context, state) {
final tab = state.pathParameters['tab']!;
return NavigationScreen(
tab: tab,
);
},
routes: const []),
]);
});
- initialLocation: 을 통해 초기시작되는 Path은 "/home" 으로 NavigationScreen을 Routing 하면서 Parameter인 ['tab']에 "home"이 전달됩니다.
*주의사항 (Router 설정주의)
- GoRouter()의 initialLocation: 속성과 같은 path 를 갖는 GoRoute()가 존재한다면 정상작동 되지않습니다.
- 같은 path가 존재할 경우, 동일한 path를 갖는 GoRoute()로 바로 연결되며, NavigationScreen()의 Parameter path가 동작하지않습니다.
(initialLocation: path와 동일한 GoRoute path가 있다면 이게 먼저 Routing되기 때문)
해결방법
- 방법 1. 좌측 그림과 같이 HomeScreen을 Routing하는 GoRoute 를 제거합니다.
- 방법 2. 우측 그림과 같이 HomeScreen은 그대로 두고, initialLocation의 path와 Parameters tab의 명칭을 바꿔줍니다.
navigation.dart (Stack, Offstage)
import 'package:flutter/material.dart';
import 'package:flutter_application_homebar/home/home_screen.dart';
import 'package:flutter_application_homebar/profile/profile_screen.dart';
import 'package:flutter_application_homebar/receipt/receipt_screen.dart';
import 'package:flutter_application_homebar/search/search_screen.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
class NavigationScreen extends ConsumerStatefulWidget {
const NavigationScreen({super.key, required this.tab});
static String routeName = "navigation";
final String tab;
@override
ConsumerState<ConsumerStatefulWidget> createState() =>
_NavigationScreenState();
}
class _NavigationScreenState extends ConsumerState<NavigationScreen> {
final List<String> _tab = ["home", "search", "receipt", "profile"];
late int _tabIndex = _tab.indexOf(widget.tab);
void _onTapNavButton(int index) {
context.go("/${_tab[index]}");
setState(() {
_tabIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
//resizeToAvoidBottomInset: 키보드 입력창이 나와도 화면이 resize되지 않게 함(false)
resizeToAvoidBottomInset: false,
body: Stack(
children: [
Offstage(
offstage: _tabIndex != 0,
child: const HomeScreen(),
),
Offstage(
offstage: _tabIndex != 1,
child: const SearchScreen(),
),
Offstage(
offstage: _tabIndex != 2,
child: const ReceiptScreen(),
),
Offstage(
offstage: _tabIndex != 3,
child: const ProfileScreen(),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GestureDetector(
onTap: () => _onTapNavButton(0),
child: Icon(
_tabIndex == 0 ? Icons.house : Icons.house_outlined,
size: 40,
)),
GestureDetector(
onTap: () => _onTapNavButton(1),
child: Icon(
_tabIndex == 1
? FontAwesomeIcons.wineGlass
: FontAwesomeIcons.wineGlassEmpty,
size: 40,
)),
GestureDetector(
onTap: () => _onTapNavButton(2),
child: Icon(_tabIndex == 2
? FontAwesomeIcons.listCheck
: FontAwesomeIcons.list)),
GestureDetector(
onTap: () => _onTapNavButton(3),
child: Icon(_tabIndex == 3
? FontAwesomeIcons.userCheck
: FontAwesomeIcons.user)),
],
),
));
}
}
- router.dart로 부터 전달받은 "home"을 tab에 저장하고 _tab의 "home" 인덱스가 0이기 때문에 _tabIndex는 0이 됩니다.
- Scaffold의 body는 Stack으로 이루어져있으며, 4개의 offstage 위젯을 자식으로 가지고있습니다.
- offstage의 자식인 4개의 Screen이 한번에 렌더링 되며, 렌더링된 모든 Screen들을 Stack에 쌓아둡니다.
- 현재 _tabIndex가 0 이기때문에 HomeScreen() 을 제외한 나머지 Screen들은 offstage 즉, 보이지않게 설정됩니다.
- 이후에도 BottomAppBar Button 클릭에 따라 _tabIndex가 아닌 Screen을 모두 Off Stage하며, 버튼의 아이콘을 바꿔줍니다.
반응형
'앱 개발 > Flutter' 카테고리의 다른 글
Comments