개발부터 자유까지
[Flutter] 코딩셰프 순한맛 18, 26 - 스낵바, BuildContext 본문
강좌 18
- 영상에서 사용하는 예전 Widget 이 더이상 사용하지 않아 현재 버전(Flutter 3.24.1) 사용하는 Widget 으로 수정하여 코딩함
- FlatButton은 더 이상 사용되지 않으며, 대신 TextButton, ElevatedButton, 또는 OutlinedButton을 사용해야되며, Scaffold.of(context).showSnackBar는 이제 ScaffoldMessenger.of(context).showSnackBar로 대체됨
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AppBar',
theme: ThemeData(primarySwatch: Colors.red),
home: const MyPage(),
);
}
}
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Snack Bar',
style: TextStyle(color: Colors.white),
),
centerTitle: true,
backgroundColor: Colors.red,
),
body: Builder(builder: (BuildContext ctx) {
return Center(
child: TextButton(
style: TextButton.styleFrom(backgroundColor: Colors.red),
onPressed: () {
ScaffoldMessenger.of(ctx)
.showSnackBar(const SnackBar(content: Text('Hello')));
},
child: const Text(
'Show me',
style: TextStyle(color: Colors.white),
),
),
);
}),
);
}
}
출처
https://youtu.be/-zxGPfjiQQA?si=jyNVh6irI2I485Bs
강좌 26(패치)
- Flutter 2.0으로 넘어오면서 SnackBar 패치가 됨
- 기존 Scaffold.of(context).showSnackBar 가 deprecated 된 이유
- 아래 그림처럼, 주문확인 페이지에서 "주문이 접수되었습니다" snackbar가 올라오는데 새로운 배송알림 페이지에서는 snackbar를 유지되지 않고 에러 발생한다.
- 이유는 주문확인 페이지에서 구현된 snackbar는 주문확인 페이지 안에 있는 BuildContext의 Scaffold에서만 구현이 되어 있기 때문. 배송알림 페이지로 이동하면 새로운 BuildContext에 있는 Scaffold로 바뀌게 되고 snackbar는 더 이상 구현이 될 수 없다.
- Flutter 2.0에서 해결한 방법
- 최상위 트리 위젯에서 ScaffoldMessenger를 사용해 여러 자손 Scaffold들을 등록해서 snackbar가 어디서든 유지될 수 있게 관리한다.
- 기본적으로 루트 ScaffoldMessenger는 MaterialApp에 포함되므로 위 상황을 가능하게 한다.
- 그림 순서에서 마지막 "좋아요"가 취소되었습니다 snackbar가 뜬 채로 첫 페이지로 돌아가도 snackbar가 유지되고 있다.
// main.dart
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyPage(),
);
}
}
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Scaffold Messenger'),
backgroundColor: Colors.orange,
),
body: HomeBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Like a new Snack bar!'),
duration: const Duration(seconds: 5),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ThirdPage()));
},
),
),
);
},
child: const Icon(Icons.thumb_up),
),
);
}
}
class HomeBody extends StatelessWidget {
const HomeBody({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => SecondPage()));
},
child: const Text('Go to the second page')),
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second Page'),
backgroundColor: Colors.green,
),
body: const Center(
child: Text(
'"좋아요가 추가되었습니다"',
style: TextStyle(fontSize: 20.0, color: Colors.redAccent),
),
),
);
}
}
class ThirdPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Third Page'),
backgroundColor: Colors.blue,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'"좋아요를 취소하시겠습니까?"',
style: TextStyle(fontSize: 20.0, color: Colors.redAccent),
),
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('"좋아요"가 취소되었습니다.'),
duration: Duration(seconds: 3),
));
},
child: const Text('취소하기'))
],
),
),
);
}
}
- 페이지 이동시 snackbar를 사라지게 하려면 어떻게 해야할까?
- root ScaffoldMessenger가 아니라 페이지마다의 개별적인 ScaffoldMessenger를 생성해야한다.
- 개별적인 ScaffoldMessenger는 root ScaffoldMessenger가 아니기 때문에 자손 Scaffold 정보가 없다. 그러므로 Scaffold 아래서 Builder 위젯으로 새로운 context를 생성 후, ScaffoldMessenger.of(context)에 전달해줘야 한다.
달라진 Third Page 코드
class ThirdPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScaffoldMessenger(
child: Scaffold(
appBar: AppBar(
title: const Text('Third Page'),
backgroundColor: Colors.blue,
),
body: Builder(builder: (context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'"좋아요를 취소하시겠습니까?"',
style: TextStyle(fontSize: 20.0, color: Colors.redAccent),
),
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('"좋아요"가 취소되었습니다.'),
duration: Duration(seconds: 3),
));
},
child: const Text('취소하기'))
],
),
);
}),
),
);
}
}
출처
https://docs.flutter.dev/release/breaking-changes/scaffold-messenger
SnackBars managed by the ScaffoldMessenger
SnackBars are now managed by the ScaffoldMessenger, and persist across routes.
docs.flutter.dev
https://api.flutter.dev/flutter/material/ScaffoldMessenger-class.html
ScaffoldMessenger class - material library - Dart API
Manages SnackBars and MaterialBanners for descendant Scaffolds. This class provides APIs for showing snack bars and material banners at the bottom and top of the screen, respectively. To display one of these notifications, obtain the ScaffoldMessengerState
api.flutter.dev
'Flutter' 카테고리의 다른 글
[Flutter] 코딩셰프 순한맛 20 - 컨테이너 위젯 (0) | 2024.09.12 |
---|---|
[Flutter] 코딩셰프 순한맛 19 - Builder Widget 없이 스낵바 구현, 토스트 메세지 구현하기 (0) | 2024.09.10 |
[Flutter] 코딩쉐프 순한맛 강좌 14 - 메뉴 아이콘 추가하기 (0) | 2024.09.08 |
[Flutter] windows에 flutter 설치시 이슈 (0) | 2024.08.29 |
[Flutter] UI 그리기 연습(5) - 반복되는 카드를 하나의 위젯으로 (0) | 2023.08.07 |