Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Archives
Today
Total
관리 메뉴

개발부터 자유까지

[Flutter] 코딩셰프 순한맛 18, 26 - 스낵바, BuildContext 본문

Flutter

[Flutter] 코딩셰프 순한맛 18, 26 - 스낵바, BuildContext

건물주개발자 2024. 9. 9. 00:43

강좌 18

  • 영상에서 사용하는 예전 Widget 이 더이상 사용하지 않아 현재 버전(Flutter 3.24.1) 사용하는 Widget 으로 수정하여 코딩함
  • FlatButton은 더 이상 사용되지 않으며, 대신 TextButton, ElevatedButton, 또는 OutlinedButton을 사용해야되며, Scaffold.of(context).showSnackBar는 이제 ScaffoldMessenger.of(context).showSnackBar로 대체됨

버튼 클릭 후 snack bar에 Hello

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 1.0에서 snackbar가 라우팅시 유지될 수 없는 이유

  • Flutter 2.0에서 해결한 방법
    •  최상위 트리 위젯에서 ScaffoldMessenger를 사용해 여러 자손 Scaffold들을 등록해서 snackbar가 어디서든 유지될 수 있게 관리한다.
    • 기본적으로 루트 ScaffoldMessenger는 MaterialApp에 포함되므로 위 상황을 가능하게 한다.

https://docs.flutter.dev/release/breaking-changes/scaffold-messenger

 

 

  • 그림 순서에서 마지막 "좋아요"가 취소되었습니다 snackbar가 뜬 채로 첫 페이지로 돌아가도 snackbar가 유지되고 있다.

 

첫화면 -> 따봉 클릭 -> undo 클릭 -> 세번째 페이지 -> 취소하기 클릭 ->
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)에 전달해줘야 한다.

취소하기로 snackbar -> 첫페이지로 이동시 snackbar사라짐

 

 

달라진 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