Scaffold 與 MaterialApp


現今來說,App 使用者介面往往有著類似的樣貌,這些樣貌是諸多使用者的經驗促成的,在對使用者介面沒有什麼特別想法的情況下,往往就會採用這類樣貌,這一方面也是為了避免造成使用者意料之外的行為,從而產生對 App 使用上的疑惑。

例如,不少 App 可能會有這樣的版面:

Scaffold 與 MaterialApp

搭建這類版面的方式之一,是從頭到尾自行建構:

import 'package:flutter/material.dart';

void main() => runApp(
  Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Container(
        color: Colors.blue,
        height: 100,
        child: Center(
          child: Text(
            'Flutter 筆記',
            textDirection: TextDirection.ltr,
            textAlign: TextAlign.center,
          )
        ),
      ),
      Expanded(           // 儘可能擴展元件填滿可用空間
        child: Container(
          color: Colors.white,
          child: Text(
            '內容...',
            textDirection: TextDirection.ltr,
            style: TextStyle(color: Colors.black)
          ),
        )
      ),
      Container(
        color: Colors.cyan,
        height: 80,
        child: Center(
          child: Text(
            '版權...',
            textDirection: TextDirection.ltr,
            textAlign: TextAlign.center,
          )
        ),
      )
    ]
  )
);

因為這類佈局架構很常使用,或許你會想要定義一個通用的 AppScaffold 鷹架元件:

import 'package:flutter/material.dart';

void main() => runApp(
  AppScaffold(
    title: Text(
      'Flutter 筆記',
      textDirection: TextDirection.ltr,
      textAlign: TextAlign.center,
    ),
    body: Text(
        '內容...',
        textDirection: TextDirection.ltr,
        style: TextStyle(color: Colors.black)
    ),
    footer: Text(
      '版權...',
      textDirection: TextDirection.ltr,
      textAlign: TextAlign.center,
    ),
  )
);

class AppScaffold extends StatelessWidget {
  final Widget title;
  final Widget body;
  final Widget footer;

  AppScaffold({this.title, this.body, this.footer});

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Container(
            color: Colors.blue,
            height: 100,
            child: Center(child: title),
          ),
          Expanded(
              child: Container(
                color: Colors.white,
                child: body,
              )
          ),
          Container(
            color: Colors.cyan,
            height: 80,
            child: Center(child: footer),
          )
        ]
    );
  }
}

隨著你建立的 App 越多,這個 AppScaffold 可能因不斷重用、重構而越來越通用,例如,可以自訂顏色、為了能有因應操作產生畫面變化,改繼承 StatefulWidget 等…

實際上,Flutter 就有個通用的 Scaffold 類別可以使用,必須搭配 MaterialApp

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text(
          'Flutter 筆記',
          textDirection: TextDirection.ltr,
        ),
      ),
      body: Text(
        '內容...',
        textDirection: TextDirection.ltr,
      ),
      bottomNavigationBar: BottomAppBar(
        color: Colors.cyan,
        child: Text(
          '版權...',
          textDirection: TextDirection.ltr,
          textAlign: TextAlign.center,
        )
      ),
    ),
  )
);

執行結果如下:

Scaffold 與 MaterialApp

Material Design 是一套設計指南,目的是為了介面設計可營造最佳的使用者經驗,簡單來說,對於平面螢幕裝置的介面設計(手機 App、Web 網頁,甚至是桌面應用程式),Material Design 主張不侷促於實體元件的模擬(例如在手機螢幕中模擬實體世界的立體按鈕),畢竟電子螢幕中的數位元素,本質上不存在於實體世界中,應該要去重新定義數位元素本身應有樣貌、彈性與屬性的一種設計。

MaterialApp 是個用來實作 Material Design 風格的支援類別,實際上至今使用的 material 套件中的元件也都是用來支援 Material Design。

Scaffold 是通用的鷹架元件,MaterialApp 是用來支援 Material Design,想當然爾,可設定的細節很多,例如,改變一下佈景主題:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    theme: ThemeData(
      brightness: Brightness.dark,
      primaryColor: Colors.yellow
    ),
    home: Scaffold(
      appBar: AppBar(
        title: Text(
          'Flutter 筆記',
          textDirection: TextDirection.ltr,
        ),
      ),
      body: Text(
        '內容...',
        textDirection: TextDirection.ltr,
      ),
      bottomNavigationBar: BottomAppBar(
        child: Text(
          '版權...',
          textDirection: TextDirection.ltr,
          textAlign: TextAlign.center,
        )
      ),
    ),
  )
);

執行結果:

Scaffold 與 MaterialApp

類似地,因為可設定的細節很多,單純談每個設定細節是極其無聊的一件事,日後有用到的場景,再做相關說明會是比較好的方式。