openplanning

Hướng dẫn và ví dụ Flutter Scaffold

  1. Scaffold
  2. Examples
  3. floatingActionButton
  4. floatingActionButtonLocation
  5. floatingActionButtonAnimator
  6. drawer
  7. endDrawer
  8. drawerDragStartBehavior
  9. bottomNavigationBar
  10. persistentFooterButtons
  11. bottomSheet
  12. backgroundColor
  13. resizeToAvoidBottomPadding
  14. resizeToAvoidBottomInset
  15. primary

1. Scaffold

Lớp Scaffold là một widget có khả năng mở rộng lấp đầy không gian sẵn có hoặc lấp đầy màn hình, nó cung cấp API để hiển thị các widget chính của ứng dụng như Drawer, SnackBar, Bottom-Sheet, FloatingActionButton, AppBar, BottomNavigationBar,...
Scaffold Constructor:
Scaffold constructor
const Scaffold({
  Key key,
  PreferredSizeWidget appBar,
  Widget body,
  Widget floatingActionButton,
  FloatingActionButtonLocation floatingActionButtonLocation,
  FloatingActionButtonAnimator floatingActionButtonAnimator,
  List<Widget> persistentFooterButtons,
  Widget drawer,
  Widget endDrawer,
  Widget bottomNavigationBar,
  Widget bottomSheet,
  Color backgroundColor,
  bool resizeToAvoidBottomPadding,
  bool resizeToAvoidBottomInset,
  bool primary: true,
  DragStartBehavior drawerDragStartBehavior:   DragStartBehavior.down
})

2. Examples

main.dart (ex1)
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'o7planning.org',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Scaffold Example'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
          child:
          Text (
            'Hello World',
          )
      ),
    );
  }
}
Trong ví dụ này chúng ta đã tạo ra một Scaffold với hai tham số: appBarbody.
Scaffold (appBar + body)
// Create a Scaffold with 2 parameters: appBar, body.
Scaffold(
  appBar: AppBar(
    title: Text('Flutter Scaffold Example'),
  ),
  body: Center(
      child:
      Text(
        'Hello World',
      )
  ),
);

3. floatingActionButton

floatingActionButton là một button nổi bên trên bề mặt của body, theo mặc định nó sẽ nổi ở góc dưới bên phải màn hình. Bạn có thể chỉ định vị trí của nó thông qua property floatingActionButtonLocation.
Widget floatingActionButton
main.dart (floatingActionButton ex1)
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

// This Widget is the main application widget.
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "o7planning.org",
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  int _count = 0;

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title:  Text('Flutter Scaffold Example'),
      ),
      body: Center(
          child: Text('You have pressed the button $_count times.')
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: ()  {
          setState(() => this._count++);
        },
        tooltip: 'Increment Counter',
        child: const Icon(Icons.add),
      ),
    );
  }
}
  • Hướng dẫn và ví dụ Flutter FloatingActionButton

4. floatingActionButtonLocation

Property floatingActionButtonLocation được sử dụng để chỉ định vị trí hiển thị của floatingActionButton. Giá trị mặc định của nó là FloatingActionButtonLocation.endFloat.
FloatingActionButtonLocation floatingActionButtonLocation
Ví dụ:
Scaffold (floatingActionButtonLocation ex1)
Scaffold(
  appBar: AppBar(
    title:  Text('Flutter Scaffold Example'),
  ),
  body: Center(
      child: Text('Hello World')
  ),
  bottomNavigationBar: BottomAppBar(
    shape: CircularNotchedRectangle(),
    color: Colors.black12,
    child: Container(
      height: 50.0,
    ),
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: () {},
    tooltip: 'Increment Counter',
    child: Icon(Icons.add),
  ),
  floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
Lớp FloatingActionButtonLocation cho phép bạn định nghĩa vị trí hiển thị của FloatingActionButton, một vài vị trí đã được định nghĩa sẵn như những hằng số tĩnh của lớp này:
  • FloatingActionButtonLocation.centerDocked
  • FloatingActionButtonLocation.centerFloat
  • FloatingActionButtonLocation.centerTop
  • FloatingActionButtonLocation.endDocked
  • FloatingActionButtonLocation.endFloat
  • FloatingActionButtonLocation.endTop
  • FloatingActionButtonLocation.miniCenterDocked
  • FloatingActionButtonLocation.miniCenterFloat
  • FloatingActionButtonLocation.miniCenterTop
  • FloatingActionButtonLocation.miniEndDocked
  • FloatingActionButtonLocation.miniEndFloat
  • FloatingActionButtonLocation.miniEndTo
  • FloatingActionButtonLocation.miniStartDocked
  • FloatingActionButtonLocation.miniStartFloat
  • FloatingActionButtonLocation.miniStartTop
  • FloatingActionButtonLocation.startDocked
  • FloatingActionButtonLocation.startFloat
  • FloatingActionButtonLocation.startTop
*Docked
Các hằng số startDocked, centerDocked, endDocked, miniStartDocked, miniCenterDocked, miniEndDocked cho phép Scaffold.floatingActionButton hiển thị ở phía trên bề mặt Scaffold.body, sao cho tâm của button thẳng hàng với viền phía trên của Scaffold.bottomSheet hoặc Scaffold.persistentFooterButtons hoặc Scaffold.bottomNavigationBar (Theo thứ tự ưu tiên như vậy)
Nếu Scaffold.bottomSheetScaffold.persistentFooterButtonsnull, và Scaffold.bottomNavigationBar là một đối tượng BottomAppBar thì Scaffold.floatingActionButton sẽ tạo ra một vết khắc (notch) trên bề mặt của Scaffold.bottomNavigationBar.
*Float
Các hằng số startFloat, centerFloat, endFloat, miniStartFloat, miniCenterFloat, miniEndFloat cho phép Scaffold.floatingActionButton hiển thị ở phía trên và không chồng chéo với cả hai widget: Scaffold.persistentFooterButtonsScaffold.bottomNavigationBar.
Nếu Scaffold.bottomSheet khác null, tâm của Scaffold.floatingActionButton sẽ thẳng hàng với viền trên của Scaffold.bottomSheet.
*Top
Các hằng số startTop, centerTop, endTop, miniStartTop, miniCenterTop, miniEndTop cho phép Scaffold.floatingActionButton hiển thị ngay phía dưới thanh công cụ ở trên cùng sao cho tâm của button thẳng hàng với viền phía dưới của thanh công cụ.
mini*
Các hằng số có tiếp đầu ngữ "mini" làm cho Scaffold.floatingActionButton có kích thước nhỏ hơn thông thường một chút, nó tương đương với việc sét đặt FloatingActionButton.mini = true.

5. floatingActionButtonAnimator

Property floatingActionButtonAnimator này được sử dụng để tạo ra hiệu ứng hoạt hình cho FloatingActionButton.
FloatingActionButtonAnimator floatingActionButtonAnimator

6. drawer

drawer là một Panel hiển thị bên cạnh trái của body (Nếu textDirection = TextDirection.ltr). Thông thường nó ở trạng thái ẩn trên các thiết bị di động. Bạn cần vuốt từ trái sang phải để làm nó xuất hiện.
Widget drawer
Trong một vài tình huống một button có thể được tự động thêm vào AppBar.leading hoặc AppBar.actions để giúp người dùng nhanh chóng mở ra drawer, nó được giải thích ở bài viết dưới đây:
Ví dụ:
main.dart (drawer)
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Scaffold Example'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold (
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
          child:
          Text(
            'Hello World',
          )
      ),
      drawer: Drawer(
        child: ListView(
          children: const <Widget> [
            DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.green,
              ),
              child: Text(
                'Hello World',
                style: TextStyle(
                  color: Colors.green,
                  fontSize: 24,
                ),
              ),
            ),
            ListTile(
              title: Text('Gallery'),
            ),
            ListTile(
              title: Text('Slideshow'),
            ),
          ],
        ),
      ),
    );
  }
}

7. endDrawer

endDrawer là một Panel hiển thị bên cạnh phải của body (Nếu textDirection = TextDirection.ltr). Thông thường nó ở trạng thái ẩn trên các thiết bị di động. Bạn cần vuốt từ phải sang trái để làm nó xuất hiện.
Widget endDrawer
Trong một vài tình huống một button có thể được tự động thêm vào AppBar.leading hoặc AppBar.actions để giúp người dùng nhanh chóng mở ra drawer, nó được giải thích ở bài viết dưới đây:
Ví dụ:
main.dart (endDrawer ex1)
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'o7planning.org',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Scaffold Example'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold (
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
          child:
          Text(
            'Hello World',
          )
      ),
      endDrawer: Drawer(
        child: ListView(
          children: const <Widget> [
            DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.green,
              ),
              child: Text(
                'Hello World',
                style: TextStyle(
                  color: Colors.green,
                  fontSize: 24,
                ),
              ),
            ),
            ListTile(
              title: Text('Gallery'),
            ),
            ListTile(
              title: Text('Slideshow'),
            ),
          ],
        ),
      ),
    );
  }
}

8. drawerDragStartBehavior

DragStartBehavior drawerDragStartBehavior:   DragStartBehavior.down

9. bottomNavigationBar

bottomNavigationBar là một thanh điều hướng hiển thị ở dưới cùng của Scaffold, trong hầu hết các trường hợp sử dụng nó là một đối tượng BottomAppBar hoặc BottomNativationBar.
Widget bottomNavigationBar
Scaffold (buttomNavigationBar)
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Scaffold Example'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Center(
          child: Text('Hello World')
      ),
      bottomNavigationBar : BottomNavigationBar(
          currentIndex : 0,
          fixedColor  : Colors.green,
          items : [
            BottomNavigationBarItem(
              title  : Text("Home"),
              icon  : Icon(Icons.home),
            ),
            BottomNavigationBarItem(
              title : Text("Search"),
              icon  : Icon(Icons.search),
            ),
            BottomNavigationBarItem(
              title  : Text("Profile"),
              icon  : Icon(Icons.account_circle),
            ),
          ],
          onTap  : (int indexOfItem) {

          }),
    );
  }
}

10. persistentFooterButtons

persistentFooterButtons là một danh sách các button được gói trong một ButtonBar, hiển thị phía dưới cùng của Scaffold, chúng kiên trì hiển thị kể cả khi người dùng cuộn body của Scaffold. Trong hầu hết các trường hợp sử dụng chúng là các TextButton.
List<Widget> persistentFooterButtons
Ví dụ, một Scaffold với persistentFooterButtons và không bao gồm bottomNavigationBar:
persistentFooterButtons (ex1)
Scaffold(
    appBar: AppBar(
      title:  Text('Flutter Scaffold Example'),
    ),
    body: Center(
        child: Text('Hello World')
    ),
    persistentFooterButtons :  [
      TextButton.icon(icon: Icon(Icons.map), label: Text(""), onPressed: () {}),
      TextButton.icon(icon: Icon(Icons.view_week), label: Text(""), onPressed: () {}),
    ]
)
Ví dụ, một Scaffold với persistentFooterButtonsbottomNavigationBar:
persistentFooterButtons (ex2)
Scaffold(
    appBar: AppBar(
      title:  Text('Flutter Scaffold Example'),
    ),
    body: Center(
        child: Text('Hello World')
    ),
    persistentFooterButtons :  [
      TextButton.icon(icon: Icon(Icons.map), label: Text(""), onPressed: () {}),
      TextButton.icon(icon: Icon(Icons.view_week), label: Text(""), onPressed: () {}),
    ],
    bottomNavigationBar: BottomAppBar(
      color: Colors.lightGreen[200],
      child: new Row(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[
          TextButton.icon(icon: Icon(Icons.home), label: Text(""), onPressed: () {},),
          TextButton.icon(icon: Icon(Icons.email), label: Text(""), onPressed: () {},),
        ],
      ),
    )
)

11. bottomSheet

bottomSheet hiển thị một thông tin bổ xung cho nội dung chính của ứng dụng, nó kiên trì hiển thị ở gần cuối cùng của Scaffold ngay cả khi người dùng tương tác với các phần khác của ứng dụng.
Widget bottomSheet
Mặc dù bottomSheet đứng ở phía cuối của Scaffold nhưng nó vẫn đứng trước persistentFooterButtonsbottomNavigationBar.
bottomSheet (ex1)
Scaffold(
    appBar: AppBar(
      title:  Text('Flutter Scaffold Example'),
    ),
    body: Center(
        child: Text('Hello World')
    ),
    bottomSheet: Container(
        height: 55,
        color: Colors.cyan[50],
        child:Column    (
          children: [
            Row (
              children: [
                Icon(Icons.place),
                SizedBox(width:5, height:5),
                Text("199 Valencia St, San Francisco, CA")
              ],
            ),
            Row (
              children: [
                Icon(Icons.phone),
                SizedBox(width:5, height:5),
                Text("(415) 339-0942)")
              ],
            )
          ],
        )
    ),
    persistentFooterButtons :  [
      TextButton.icon(icon: Icon(Icons.map), label: Text(""), onPressed: () {}),
      TextButton.icon(icon: Icon(Icons.view_week), label: Text(""), onPressed: () {}),
    ],
    bottomNavigationBar: BottomAppBar(
      color: Colors.lightGreen[200],
      child: new Row(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[
          TextButton.icon(icon: Icon(Icons.home), label: Text(""), onPressed: () {},),
          TextButton.icon(icon: Icon(Icons.email), label: Text(""), onPressed: () {},),
        ],
      ),
    )
)
ScaffoldState.showButtonSheet()
Phương thức ScaffoldState.showBottomSheet() được sử dụng để tạo và hiển thị bottomSheet cho Scaffold khi cần thiết và người dùng có thể đóng bottomSheet để tiết kiệm không gian cho ứng dụng.
main.dart (bottomSheet ex2)
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

// This Widget is the main application widget.
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "o7planning.org",
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {


  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title:  Text('Flutter Scaffold Example'),
        ),
        body: Center(
          child: Center(
              child:  Builder ( // The Builder return a ElevatedButton
                // We need a context of Scaffold
                builder: (BuildContext ctxOfScaffold)  {
                  return  ElevatedButton(
                    onPressed: ()  {
                      this._showMyBottomSheet(ctxOfScaffold);
                    },
                    child: Icon(Icons.add),
                  );
                },
              )
          ),
        ),
        floatingActionButton: Builder ( // The Builder return a FloatingActionButton
          // We need a context of Scaffold
          builder: (BuildContext ctxOfScaffold)  {
            return  FloatingActionButton(
              onPressed: ()  {
                this._showMyBottomSheet(ctxOfScaffold);
              },
              tooltip: 'Increment Counter',
              child: Icon(Icons.add),
            );
          },
        ),
        bottomNavigationBar: BottomAppBar(
          color: Colors.lightGreen[200],
          child: new Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              TextButton.icon(icon: Icon(Icons.home), label: Text(""), onPressed: () {},),
              TextButton.icon(icon: Icon(Icons.email), label: Text(""), onPressed: () {},),
            ],
          ),
        )
    );
  }

  // We need a context object of Scaffold to draw Scaffold.bottomSheet.
  void _showMyBottomSheet(BuildContext ctxOfScaffold)  { // context of Scaffold.

    // ScaffoldState.showBottomSheet:
    Scaffold.of(ctxOfScaffold).showBottomSheet<void>(
          (BuildContext context) {
        return Container(
          height: 200,
          color: Colors.amber,
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                const Text('BottomSheet'),
                ElevatedButton(
                  child: Text('Close BottomSheet'),
                  onPressed: () => Navigator.pop(context),
                )
              ],
            ),
          ),
        );
      },
    );
  }
}
showModalBottomSheet()
Hàm showModalBottomSheet() để tạo và hiển thị một Dialog chứa một bottom-sheet, nó nổi bên trên tất cả các thành phần khác của ứng dụng, người dùng phải đóng nó lại nếu muốn tương tác với các thành phần bên dưới nó.
main.dart (bottomSheet ex3)
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'o7planning.org',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Scaffold Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Click the floating action button to show bottom sheet.',
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed:() =>  _showMyBottomSheet(context),
          child: Icon(Icons.add),
        ),
        bottomNavigationBar: BottomAppBar(
          color: Colors.lightGreen[200],
          child: new Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              TextButton.icon(icon: Icon(Icons.home), label: Text(""), onPressed: () {},),
              TextButton.icon(icon: Icon(Icons.email), label: Text(""), onPressed: () {},),
            ],
          ),
        )
    );
  }


  void _showMyBottomSheet(BuildContext context) {
    // Call showModalBottomSheet(), this function open a Dialog
    // and return Future object.
    showModalBottomSheet (
        context: context,
        builder: (ctx) {
          return Container(
            height: MediaQuery.of(context).size.height  * 0.4,
            child: Center(
              child: Text("Welcome to o7planning.org!"),
            ),
          );
        }
    );
  }
}

12. backgroundColor

Property backgroundColor được sử dụng để sét đặt mầu nền của Scaffold.
Color backgroundColor
Ví dụ:
backgroundColor (ex1)
Scaffold(
  appBar: AppBar(
    title:  Text('Flutter Scaffold Example'),
  ),
  body: Center(
      child: Text('Hello World')
  ),
  backgroundColor: Colors.greenAccent,
)

13. resizeToAvoidBottomPadding

bool resizeToAvoidBottomPadding

14. resizeToAvoidBottomInset

bool resizeToAvoidBottomInset

15. primary

bool primary: true

Các hướng dẫn lập trình Flutter

Show More