iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
0
Mobile Development

Flutter 程式設計入門實戰 30 天系列 第 18

Day 18:SnackBar 提示元件

  • 分享至 

  • xImage
  •  

2024 最新 Flutter 教學 - Flutter 終極指南: 連結
從零開始學 Dart 程式設計: 連結
Flutter 程式設計入門實戰 30 天: 連結


哈囉~大家好,我是 KT ,今天【iT邦幫忙鐵人賽】挑戰第十八天,KT 將為大家來介紹,SnackBar 提示元件。

SnackBar 提示元件

SnackBar 提示元件,會在螢幕下方,彈跳顯示訊息,幾秒後消失。

範例:顯示 SnackBar 簡單基本訊息

final snackBar = new SnackBar(content: new Text('顯示訊息'));
Scaffold.of(context).showSnackBar(snackBar);

執行畫面

完整程式碼

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(
        title: Text('HKT線上教室'),
      ),
      body: HomePage(),
    ));
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: Text('顯示 SnackBar 訊息'),
        onPressed: () {
        //顯示 SnackBar 簡單基本訊息
          final snackBar = new SnackBar(content: new Text('顯示訊息'));
          Scaffold.of(context).showSnackBar(snackBar);
        },
      ),
    );
  }
}

範例:錯誤示範完整程式碼

注意事項:
SnackBar 要顯示訊息是透過 Scaffold的showSnackBar 方法來顯示。所以要顯示訊息,務必要先拿到 Scaffold 的 context,否則會報錯無法顯示。當然可以直接在 body 後包一層 Builder 快速解決,不過 KT 建議不要寫出波動拳程式結構。所以在最一開始起手式章節 KT 就直接建議拆開,分成一小塊一小塊邏輯程式,維護、閱讀比較方便,降低程式耦合性比較容易擴充與變動。

/*
 * 錯誤程式,執行會發生錯誤
 */
 
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(
        title: Text('HKT線上教室'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('顯示 SnackBar 訊息'),
          onPressed: () {
            final snackBar = new SnackBar(content: new Text('顯示訊息'));
            Scaffold.of(context).showSnackBar(snackBar);
          },
        ),
      ),
    ));
  }
}

執行後會出現錯誤

會出現類似下方,錯誤 Log 訊息

flutter: ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
flutter: The following assertion was thrown while handling a gesture:
flutter: Scaffold.of() called with a context that does not contain a Scaffold.
flutter: No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This
flutter: usually happens when the context provided is from the same StatefulWidget as that whose build
flutter: function actually creates the Scaffold widget being sought.
flutter: There are several ways to avoid this problem. The simplest is to use a Builder to get a context that
flutter: is "under" the Scaffold. For an example of this, please see the documentation for Scaffold.of():
flutter:   https://api.flutter.dev/flutter/material/Scaffold/of.html
flutter: A more efficient solution is to split your build function into several widgets. This introduces a
flutter: new context from which you can obtain the Scaffold. In this solution, you would have an outer widget
flutter: that creates the Scaffold populated by instances of your new inner widgets, and then in these inner
flutter: widgets you would use Scaffold.of().
flutter: A less elegant but more expedient solution is assign a GlobalKey to the Scaffold, then use the
flutter: key.currentState property to obtain the ScaffoldState rather than using the Scaffold.of() function.
flutter: The context used was:
flutter:   MyApp
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      Scaffold.of (package:flutter/src/material/scaffold.dart:1188:5)
flutter: #1      MyApp.build.<anonymous closure> (package:demo_flutter/main.dart:20:22)
flutter: #2      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:635:14)
flutter: #3      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:711:32)
flutter: #4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
flutter: #5      TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)
flutter: #6      TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:275:7)
flutter: #7      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:455:9)
flutter: #8      PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:75:13)
flutter: #9      PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:102:11)
flutter: #10     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
flutter: #11     _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
flutter: #12     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
flutter: #13     _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
flutter: #14     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
flutter: #18     _invoke1 (dart:ui/hooks.dart:250:10)
flutter: #19     _dispatchPointerDataPacket (dart:ui/hooks.dart:159:5)
flutter: (elided 3 frames from package dart:async)
flutter:
flutter: Handler: "onTap"
flutter: Recognizer:
flutter:   TapGestureRecognizer#90ba4
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════

範例:顯示 SnackBar 訊息與自定義按鈕

void showMySnackBar(BuildContext context) {
    final snackBar = new SnackBar(
      content: new Text('顯示訊息'),
      action: SnackBarAction(
        label: '復原',
        onPressed: () {
          print('復原...');
        },
      ),
    );
    Scaffold.of(context).showSnackBar(snackBar);
  }

執行畫面

完整程式碼

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(
        title: Text('HKT線上教室'),
      ),
      body: HomePage(),
    ));
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: Text('顯示 SnackBar 訊息'),
        onPressed: () {
          showMySnackBar(context);
        },
      ),
    );
  }

  //顯示 SnackBar 訊息與自定義按鈕
  void showMySnackBar(BuildContext context) {
    final snackBar = new SnackBar(
      content: new Text('顯示訊息'),
      action: SnackBarAction(
        label: '復原',
        onPressed: () {
          print('復原...');
        },
      ),
    );
    Scaffold.of(context).showSnackBar(snackBar);
  }
}

那今天【iT邦幫忙鐵人賽】就介紹到這邊囉~

順帶一提,KT 線上教室,臉書粉絲團,會不定期發佈相關資訊,不想錯過最新資訊,不要忘記來按讚,加追蹤喔!也歡迎大家將這篇文章分享給更多人喔。

我們明天見囉!!!掰掰~

參考資料

HKT 線上教室
http://tw-hkt.blogspot.com/

Background vector created by freepik
www.freepik.com


上一篇
Day 17:FloatingActionButton 漂浮按鈕
下一篇
Day 19:對話框視窗
系列文
Flutter 程式設計入門實戰 30 天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Samuel.T.Chou
iT邦新手 5 級 ‧ 2023-03-21 00:18:16

版本過時:現在需要使用 ScaffoldMessenger:

final snackBar = SnackBar(content: Text('Hello'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);

我要留言

立即登入留言