본문 바로가기
flutter/Widget of the Week

Flutter[플러터] / SnackBar 를 사용하여 화면에 알림 메시지 띄우기 (경고 창, 스낵바, showSnackBar, native, Kotlin, 토스트) SnackBar (Flutter Widget of the Week)

by ch5c 2025. 6. 25.
반응형

SnackBar class

화면 하단에 잠깐 표시되는 선택적 작업이 포함된 가벼운 메시지입니다.

SnackBar 를 표시하려면 메시지를 설명하는 ScaffoldMessenger.of(context).showSnackBar() 인스턴스를 전달하여 호출합니다.

SnackBar가 표시되는 시간을 제어하려면 기간을 지정합니다 .

TalkBack이나 VoiceOver가 활성화되어 있어도 동작이 포함된 스낵바의 시간제한은 적용되지 않습니다. 이는 AccessibilityFeatures.accessibleNavigation 으로 제어됩니다.

페이지 전환 시 스낵바는 다른 페이지의 위치로 부드럽게 애니메이션이 적용됩니다. 예를 들어, SnackBar.behavior 가 SnackBarBehavior.floating 으로 설정되어 있고 다음 페이지에는 플로팅 액션 버튼이 있지만 현재 페이지에는 없는 경우, 스낵바는 플로팅 액션 버튼 위에서 부드럽게 애니메이션이 적용됩니다. 뒤로 이동 제스처 전환 시에도 작동합니다.

https://youtu.be/zpO6n_oZWw0

공식 문서 코드

 

 

 


회원가입 기능을 구현해야 할 때 보통 아이디는 몇 자 이상, 비밀번호는 몇 자 이상 이런 것을 텍스트 피르 바로 밑에 오류 메시지로 보이게도 만들지만 직접적으로 화면에 알림 창을 띄워서 유저에게 알려줄 수도 있다. 그러한 알림 기능을 막상 구현하려 한다면 조금 막막한 것이 현실일 것이다. 하지만 여기에 그러한 동작을 아주 간단히 만들 수 있는 위젯이 있는데 바로 SnackBar 위젯이다.

SnackBar 위젯은 사용자에게 간단한 메시지를 잠시 동안 화면 하단에 표시하는 위젯이다.

일반적으로 작업의 결과를 알려주거나 사용자의 액션에 대한 피드백을 줄 때 사용됩니다. 예: "저장되었습니다", "삭제되었습니다" 같은 메시지를 보여줄 때 사용되곤 한다. 바로 알아보자.

하위 속성
속성명 타입 기본값 설명
content Widget SnackBar에 표시할 기본 콘텐츠 (보통 Text)
backgroundColor Color? null 배경색 지정
elevation double? null 그림자 깊이를 설정
margin EdgeInsetsGeometry? null floating일 때 외부 여백 지정
padding EdgeInsetsGeometry? null 내용과 액션 내부 여백 지정
width double? null floating일 때 너비 지정 (margin과 동시 사용 불가)
shape ShapeBorder? null 모양 지정 (예: 테두리 둥글게)
hitTestBehavior HitTestBehavior? null 터치 이벤트 처리 방식 설정
behavior SnackBarBehavior? fixed 위치 및 동작 방식 (fixed 또는 floating)
action SnackBarAction? null 사용자가 수행할 수 있는 단일 액션 추가
actionOverflowThreshold double? 0.25 액션이 줄 바꿈되는 너비 비율 기준
showCloseIcon bool? null 닫기 아이콘 표시 여부
closeIconColor Color? null 닫기 아이콘 색상
duration Duration 4초 SnackBar가 화면에 표시되는 시간
animation Animation<double>? null 등장/퇴장 시 애니메이션 제어
onVisible VoidCallback? null 화면에 처음 표시될 때 호출되는 콜백
dismissDirection DismissDirection? down 스와이프으로 닫는 방향
clipBehavior Clip Clip.hardEdge 내용을 경계 밖으로 잘라낼지 여부

 

사용하는 방법은 굉장히 간단하다.

SnackBar(
  content: Text('Hello!'),
)

스낵바의 파라미터인 content 에 띄우고 싶은 위젯을 넣어주면 된다. content 는 Widget 타입을 갖고 있기 때문에 굳이 텍스트가 아니더라도 원하는 모든 위젯들을 다 배치해 줄 수 있다.

그렇다면 이 SnackBar 를 어떻게 화면에 띄울까?

바로 ScaffoldMessenger 함수를 이용하면 된다.

ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(content: Text('Hello!'),),
);

ScaffoldMessenger.of(context) 로 접근하여 showSnackBar 를 사용해주면 SnackBar 를 아주 간단하게 사용해 줄 수 있다.

이제 당연하지만 함수이기 때문에 실행하려면 중괄호 안에 위치해야 한다.

TextButton(
  onPressed: () {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Hello!'),),
    );
  },
  child: Text('SnackBar'),
)

 자 근데 이렇게 바로 한 5초 만에 뚝딱 알림 메시지를 만들 수 있다. 근데 여기서 당연하게도 커스텀이 조금 가능한데 먼저 화면에 보이는 시간, 띄어져 있는 시간을 조절 가능하다.

SnackBar(content: Text('Hello!'),
  duration: Duration(milliseconds: 1500),
)

duration 값을 조절해주면 그에 맞게 화면에 보이는 시간이 달라진다. 즉 빠르게 설정하면 그냥 메시지가 툭! 하고 나왔다가 바로 사라지는 느낌이 나는 것이다.

또한 사용해 보면 알겠지만 좀 솔직히 구리다. 그래서 기본 안드로이드의 토스트 메시지처럼 공중에 띄울 수도 있다.

SnackBar(content: Text('Hello!'),
  behavior: SnackBarBehavior.floating,
)

공중에 띄우고 싶다면 behavior 에서 SnackBarBehavior.floating 속성을 이용하자.

이러면 스낵바가 공중에 띄워지게 된다.

이제 여기서 추가로 있는 파라미터들로 완벽하게 스낵바를 커스텀해줄 수 있다.

근데 여기서 "난 이런 짝퉁 말고 진짜 안드로이드 냄새나는 안드로이드에, 안드로이드에 의한, 안드로이드를 위한 토스트 메시지 보내고 싶어요!"라고 할 수 있다. 사실 장난이고 Flutter 에서는 이제 이 SnackBar 가 화면의 위에 뜨는 진짜 그런 메시지가 아니고 똑같은 위젯으로 구현되어 있다.

즉 이미 어떠한 위젯으로 화면이 가려져 있는 상태라면 스낵바가 보이지 않게 된다. 예를 들어 바텀모달시트를 사용하고 있다고 가정해 보자. 난 이제 바텀모달시트 위에 스낵바를 띄웠는데 실상은 그 아래에 스낵바가 떠서 시트에 가려져서 아무것도 보이지 않게 되는 것이다. 이럴 때에는 안드로이드의 '진짜' 화면 위에 표시되는 토스트바가 필요한데 그렇다면 진짜 네이티브와 연동하여 토스트바를 보여주면 된다. 바로 알아보자. (참고로 토스트바는 앱이 닫혀도 보이는 친구이다.)

앱이 종료되어도 나타는 토스트 메시지

일단 먼저 네이티브(코틀린)와 통신하기 위한 메서드 채널을 작성을 해야 한다.

void showToast() async {
  await MethodChannel('com.example.yourapp').invokeMethod('showToast', 'Hello World!');
}

보다시피 기본적인 메소드 채널 코드인데 일반적인 코드와는 살짝 다른 점을 알 수 있을 것이다. 바로 invokeMethod 의 두 번째 인자값을 넣는 곳에 직접적인 String 을 넣어주고 있는데 그 이유는 바로 화면에 표시되는 문구를 Flutter 에서 직접 보내줄 것이기 때문이다. 즉. 이제 이 메서드채널을 받은 안드로이드는 Hello World! 라는 토스트 메시지를 출력하게 된다는 것이다.

(전체코드)

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MaterialApp(home: Test()));

class Test extends StatefulWidget {
  const Test({super.key});

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {
  void showToast() async {
    await MethodChannel('com.example.yourapp').invokeMethod('showToast', 'Hello World!');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: TextButton(
          onPressed: () {
            showToast();
          },
          child: Text('SnackBar'),
        ),
      ),
    );
  }
}

 

그런 다음은 이제 네이티브로 당연히 넘어와야 할 것이다.

아마 역대급으로 쉬운 메서드채널 코드가 아닐까 싶다..

일단 먼저 플러터와 소통이 가능하게 해주는 configureFlutterEngine 을 사용해 준다.

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {...}

 

이제 그 안에서 메서드 채널 코드를 작성해 주면 되는데 

MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.yourapp"
).setMethodCallHandler { call, result ->

위 dart 코드에서 넣었던 통신에 필요한 패키지 이름을 넣어주고 그대로 setMethodCallHandler { call, result -> } 를 사용해 준다.

이제 이 안에서는 when 으로 걸러서 가져와 주면 된다. (근데 사실 지금 하나뿐이라 이렇게 쓰면 안 되는데 그냥 귀찮아서 이리 했다.)

(전체코드)

package com.example.yourapp

import android.widget.Toast
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.example.yourapp"
        ).setMethodCallHandler { call, result ->
            when (call.method) {
                "showToast" -> {
                    Toast.makeText(this, call.arguments as String, Toast.LENGTH_SHORT).show()
                    result.success(true)
                }
            }
        }
    }

}

 

이러면 아주 간단하게 토스트 메시지를 화면에 표시할 수 있게 된다.

 

이렇게 SnackBar 위젯에 대해서 알아보았다. 사실 뒤에 토스트 메시지를 사용하는 방법을 알아보긴 했어도 SnackBar 위젯 자체만으로 상당히 커스텀을 지원을 많이 하기 때문에 내가 앞서 말했던 것 같은 상황이 아니라면 SnackBar 만을 사용하는 것도 충분히 매력적일 것이다. 암튼 도움이 되었길 바라며 마치겠다.

 

반응형