Flutter (四) 基礎 Widgets、Material Components Widget 全面介紹

基礎 Widgets

重要概念git

一切皆組件。Flutter 全部的元素都是由組件組成。好比一個佈局元素、一個動畫、一個裝飾效果等。github

容器 Container

容器組件 Container 包含一個子 widget ,自身具有 alignment 、padding 等屬性 ,方便佈局過程當中擺放 child 。canvas

屬性api

屬性名 類型 說明
key Key 控制一個小部件如何替換樹中的另外一個小部件
alignment AlignmentGeometry 將孩子與容器內的對齊,若是 Container或者 Container 的父節點尺寸大於 child 的尺寸,該屬性設置會起做用,有不少種對齊方式。
child Widget 容器所包含的孩子
constraints BoxConstraints 添加到child上額外的約束條件
decoration Decoration 繪製在child後面的修飾,設置了Decoration的話,就不能設置color屬性,不然會報錯,此時應該在Decoration中進行顏色的設置
foregroundDecoration Decoration 繪製在child前面的裝飾
margin EdgeInsetsGeometry 圍繞在 Decoration 和 child 以外的空白區域,不屬於內容區域
padding EdgeInsetsGeometry Decoration 內部的空白區,若是有 child ,child 位於 padding 內部。
transform Matrix4 設置 Container 的變換矩陣,類型爲Matrix4
  • padding 與 margin 的不一樣之處:padding 是包含在 Content 內,而 margin 是外部邊界。設置點擊事件的話,padding 區域會響應,而 margin 區域不會響應。

簡單示例bash

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      title: 'container 示例',
      home: HomePage(),
    ));

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        margin: const EdgeInsets.all(10.0),
        color: const Color(0xFF00FF00),
        width: 200.0,
        height: 200.0,
      ),
    );
  }
}
複製代碼

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      title: 'container 示例',
      home: HomePage(),
    ));

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      constraints: BoxConstraints.expand(
        height: Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
      ),
      padding: const EdgeInsets.all(20.0),
      color: Colors.teal.shade700,
      alignment: Alignment.topRight,
      child: Text('Hello World', style: Theme.of(context).textTheme.display1.copyWith(color: Colors.white)),
      foregroundDecoration: BoxDecoration(
        image: DecorationImage(
          image: NetworkImage('https://www.example.com/images/frame.png'),
          centerSlice: Rect.fromLTRB(270.0, 180.0, 1360.0, 730.0),
        ),
      ),
      transform: Matrix4.rotationX(0.5),
    );
  }
}
複製代碼

行 Row

在水平方向上排列子 widget 的列表網絡

屬性 類型 說明
key Key 控制一個小部件如何替換樹中的另外一個小部件
children List 樹中此小部件下方的小部件
crossAxisAlignment CrossAxisAlignment 如何將孩子對齊
direction Axis 用做主軸的方向

簡單示例app

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: HomePage(),
    ));

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.blue,
        body: Center(
          child: Row(
            children: <Widget>[
              Expanded(
                child: Text(
                  '12121212 ',
                  textAlign: TextAlign.center,
                  style: TextStyle(color: Colors.white),
                ),
              ),
              Expanded(
                child: Text(
                  '555555',
                  textAlign: TextAlign.center,
                  style: TextStyle(color: Colors.white),
                ),
              ),
              Expanded(
                child: FittedBox(
                  fit: BoxFit.contain, // otherwise the logo will be tiny
                  child: const FlutterLogo(
                      style: FlutterLogoStyle.horizontal,
                  ),
                ),
              ),
            ],
          ),
        ));
  }
}

複製代碼

列 Column

在垂直方向上排列子widget的列表框架

屬性less

屬性 類型 說明
key Key 控制一個小部件如何替換樹中的另外一個小部件
children List 樹中此小部件下方的小部件
crossAxisAlignment CrossAxisAlignment 如何將孩子對齊
direction Axis 用於方向
mainAxisAlignment MainAxisAlignment 主軸方向上的對齊方式,會對child的位置起做用,默認是start
mainAxisSize MainAxisSize 在主軸方向佔有空間的值,默認是max
textDirection TextDirection 肯定水平放置孩子的順序以及如何解釋水平方向的開始和結束
verticalDirection VerticalDirection 肯定垂直放置孩子的順序以及如何解釋垂直方向的開始和結束

簡單示例dom

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: HomePage(),
    ));

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.blue,
        appBar: AppBar(
          title: Text('Row 示例'),
        ),
        body: Center(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Text('Deliver features faster',style: TextStyle(color: Colors.white,fontSize: 30.0),),
              Text('Craft beautiful UIs',style: TextStyle(color: Colors.white,fontSize: 30.0),),
              Expanded(
                child: FittedBox(
                  alignment: Alignment.bottomRight,
                  child: const FlutterLogo(),
                ),
              ),
            ],
          ),
        ));
  }
}

複製代碼

圖像 Image

顯示圖像的 Widget

構造函數

構造函數 說明
Image() 通用方法,使用 ImageProvider 實現,以下方法本質上也是使用的這個方法
Image.asset(String name,{}) 根據資源名字,加載一張資源圖片
Image.file(File file,{}) 給定一個圖片文件,加載一張本地文件圖片
Image.memory(Uint8List bytes,{}) 從 Uint8List 獲取 ImageStream,加載一張內存中的圖片
Image.network(String src,{}) 給定一個 URL,加載一張網絡圖片

屬性

屬性 類型 說明
key Key 控制一個小部件如何替換樹中的另外一個小部件
alignment AlignmentGeometry 如何在圖像範圍內對齊圖像
centerSlice Rect 當圖片須要被拉伸顯示的時候,centerSlice 定義的矩形區域會被拉伸,能夠理解成咱們在圖片內部定義來一個點 9 文件用做拉伸
color Color 若是不爲 null,則使用 colorBlendMode 將此 Color 與每一個圖像像素混合
colorBlendMode BlendMode 用於將 Color 與此圖像組合
excludeFromSemantics bool 是否從 Semantics 排除此圖像
filterQuality FilterQuality 用於設置圖像的濾清器質量
fit BoxFit 對圖像顯示的控制
gaplessPlayback bool 當圖像提供者更改時,是繼續顯示舊圖像(true)仍是簡單地顯示任何內容(false)
height double
image ImageProvider 要顯示的圖像
matchTextDirection bool 是否在 TextDirection 的方向上繪製圖像
repeat ImageRepeat 如何繪製圖像未覆蓋的佈局邊界的任何部分
semanticLable String
width double

簡單示例

import 'dart:io';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:typed_data';

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

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

//assets/images/tzd.jpg
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// debugPaintSizeEnabled = true;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Image示例demo'),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              //加載網絡圖片
              Image.network(
                'https://www.baidu.com/img/bd_logo1.png?where=super',
                width: 100.0,
                height: 100.0,
              ),

              //加載Assets
              Image.asset(
                'assets/images/tzd.jpg',
                width: 200.0,
                height: 200.0,
              ),

              //Memory
              MemoryImageWidget(),

              //從文件加載圖片
              FileImageWidget(),
            ],
          ),
        ),
      ),
    );
  }
}

class FileImageWidget extends StatefulWidget {
  @override
  _FileImageWidgetState createState() => _FileImageWidgetState();
}

class _FileImageWidgetState extends State<FileImageWidget> {
  File _image;

  Future getImge() async {
    var image = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      _image = image;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Center(
          child: _image == null
              ? Text('未選擇圖片!')
              : Image.file(
                  _image,
                  width: 200.0,
                  height: 200.0,
                ),
        ),
        FlatButton(
          onPressed: getImge,
          child: Text(
            '選擇圖片',
            style: TextStyle(
              color: Color(0xff0000ff),
            ),
          ),
        ),
      ],
    );
  }
}

//stf StatefulWidget快捷鍵, stl StatelessWidget快捷鍵
class MemoryImageWidget extends StatefulWidget {
  @override
  _MemoryImageWidgetState createState() => _MemoryImageWidgetState();
}

class _MemoryImageWidgetState extends State<MemoryImageWidget> {
  Uint8List bytes;

  @override
  void initState() {
    super.initState();
    rootBundle.load('assets/images/tzd.jpg').then((data) {
      if (mounted) {
        setState(() {
          bytes = data.buffer.asUint8List();
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final _decoration = BoxDecoration(
      image: bytes == null ? null : DecorationImage(image: MemoryImage(bytes)),
    );
    return Container(
      width: 100.0,
      height: 100.0,
      decoration: _decoration,
    );
  }
}

複製代碼

文字 Widget Text

單一格式演示的文本

屬性

屬性 類型 說明
key Key 控制一個小部件如何替換樹中的另外一個小部件
data String 要顯示的文字
locale Locale 用於在能夠以不一樣方式呈現相同Unicode字符時選擇字體,具體取決於區域設置
maxLines int 文本要跨越的可選最大行數,必要時包裝。若是文本超過給定的行數,則會根據溢出將其截斷
overFlow TextoverFlow 如何處理視覺溢出
semanticsLable String 此文本的替代語義標籤
softWrap bool 文本是否應該在軟換行符處中斷
strutStyle StrutStyle 要使用的支柱風格。 Strut樣式定義了strut,它設置了最小垂直佈局度量
style TextStyle 若是爲非null,則爲此文本使用的樣式
textAlign TextAlign 文本應如何水平對齊
textScaleFactor double 每一個邏輯像素的字體像素數。
textSpan TextSpan 要顯示爲TextSpan的文本
textDirection TextDirection 文本的方向性

簡單示例

Text(
            'Hello, How are you111111111111111111111111111111111111111111111111111111111111111111111111111111?',
            textAlign: TextAlign.center,
            overflow: TextOverflow.ellipsis, //顯示省略號
            style: TextStyle(fontWeight: FontWeight.bold),
          )
複製代碼

const Text.rich(
            TextSpan(
              text: 'Hello', // default text style
              children: <TextSpan>[
                TextSpan(text: ' beautiful ', style: TextStyle(fontStyle: FontStyle.italic)),
                TextSpan(text: 'world', style: TextStyle(fontWeight: FontWeight.bold,fontSize: 100.0)),
              ],
            ),
          )
複製代碼

圖標 Icon

一個圖形圖標 Widget,使用 IconData 中描述的字體(如圖標中的材料預約義 IconDatas)中的字形繪製

屬性

屬性 類型 說明
color Color 繪製圖標使用的 Color
icon IconData 要顯示的圖標。圖標庫 Icons 中有可用的圖標
semanticLable String 標誌位
size double 大小
textDirection TextDirection 繪製方向,通常使用不到

圖標庫

凸起來的按鈕 RaisedButton

Material Design 中的 button, 一個凸起的材質矩形按鈕 ,它能夠響應按下事件,而且按下時會帶一個觸摸效果。

屬性

屬性名 類型 默認值 說明
color Color null 組件的 Color
disabledColor Color ThemeData.disabledColor 組件禁用狀態的 Color ,默認爲主題裏的禁用 Color ,也能夠設置爲其餘 Color
onPressed VoidCallback null 當按鈕按下時會觸發此回調事件
child Widget - 按鈕的child一般爲一個Text文本組件,用來顯示按鈕的文本
enable bool true 按鈕是否爲禁用狀態
RaisedButton(
              onPressed: null,
    		// onPressed: (){},
              child: const Text('Disabled Button'),
            ),
複製代碼

腳手架 Scaffold

Material Design 佈局結構的基本實現。此類提供了用於顯示 drawer、snackbar 和底部 sheet 的API

屬性

屬性 類型 說明
appBar PreferredSizeWidget 一個應用欄,顯示在腳手架的頂部
backgroundColor Color 做爲整個腳手架基礎的材質小部件的 Color
body Widget 支架的主要內容
bottomNavigationBar Widget 底部導航欄顯示在腳手架的底部
bottomSheet widget 要顯示的持久性底部工做表
drawer widget 顯示在身體側面的面板,一般隱藏在移動設備上。從左到右( TextDirection.ltr )或從右到左( TextDirection.rtl )滑入
drawerDragStartBebavior DragStartBehavior 肯定處理拖動開始行爲的方式
endDrawer Widget 顯示在身體側面的面板,一般隱藏在移動設備上。從右到左( TextDirection.ltr )或從左到右( TextDirection.rtl )滑動
floatingActionButton Widget 顯示在身體上方的按鈕,位於右下角
floatingActionButtonAnimator FloatingActionButtonAnimator Animator 將 floatingActionButton 移動到新的floatingActionButtonLocation。
floatingActionButtonLocation FloatingActionButtonLocation 負責肯定 floatingActionButton 的去向
persistentFooterButtons List 一組顯示在腳手架底部的按鈕
primary bool 此腳手架是否顯示在屏幕頂部
resizeToAvoidBottomInset bool 若是爲 true ,則 body 和 scaffold 的浮動小部件應自行調整大小,以免屏幕鍵盤的高度由環境MediaQuery 的 MediaQueryData.viewInsets 底部屬性定義
resizeToAvoidBottomPadding bool 不推薦使用此標誌,請改用resizeToAvoidBottomInset

簡單示例

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: HomePage(),
    ));

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            RaisedButton(
              onPressed: null,
              child: const Text('Disabled Button'),
            ),
            RaisedButton(
              onPressed: null,
              child: const Text('Enabled Button'),
            ),
            RaisedButton(
              onPressed: () {},
              textColor: Colors.white,
              padding: const EdgeInsets.all(0.0),
              child: Container(
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: <Color>[Colors.red, Colors.green, Colors.blue],
                  ),
                ),
                padding: const EdgeInsets.all(10.0),
                child: Text('Gradient Button'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

複製代碼

Material Components Widgets → App結構和導航

腳手架 Scaffold

Scaffold 實現了基本的 Material Design 佈局。只要是在 Material Design 中定義過的單個界面顯示的佈局組件元素,均可以使用 Scaffold 來繪製。

參考基礎 Widget → Scaffold

應用按鈕組件 Appbar

應用按鈕組件有 AppBar 和 SliverAppBar 。它們是 Material Design 中的 AppBar ,也就是Android 中的 ToolBar 。 AppBar 和 SliverAppBar 都繼承自 StatefulWidget ,二者的區別在於 AppBar 的位置是固定在應用最上面的;而 SliverAppBar 是能夠跟隨內容滾動的。

經常使用屬性

屬性名 類型 默認值 說明
actions List null 要在標題 widget 後顯示的widget
automaticallyImplyLeading bool false 控制是否應該嘗試暗示前導widget 爲null
backgroundColor Color ThemeData.primaryColor 用於應用欄材質的 Color 。一般這應該與亮度,iconTheme ,textTheme 一塊兒設置
bottom PreferredSizeWidget null 此小部件顯示在應用欄的底部
bottomOpacity double 應用欄底部的不透明程度
brightness Brightness ThemeData.primaryColorBrightness 應用欄材質的亮度。一般,這與backgroundColor,iconTheme,textTheme一塊兒設置。
centerTitle bool false 標題是否應該居中
elevation double 4 將此應用欄相對於其父級放置的 z 座標
flexibleSpace Widget null 此小組件堆疊在工具欄和標籤欄後面。它的高度與應用欄的總體高度相同
iconTheme IcomThemData ThemeData.primaryIconTheme 用於應用欄圖標的 Color ,不透明度和大小。一般,這與backgroundColor,brightness,textTheme一塊兒設置
leading Widget null 要在標題以前顯示的小部件
preferredSize Size 高度爲kToolbarHeight和底部窗口小部件首選高度之和的大小
primary bool 此應用欄是否顯示在屏幕頂部
textTheme TextTheme ThemeData.primaryTextTheme 應用欄中用於文本的排版樣式。一般,這與亮度backgroundColor,iconTheme一塊兒設置
title Widget null appbar中顯示的主要小部件
titleSpacing double 橫軸上標題內容周圍的間距。即便沒有前導內容或操做,也會應用此間距。若是但願title佔用全部可用空間,請將此值設置爲 0.0
toolbarOpacity double 應用欄的工具欄部分是多麼不透明

簡單示例

AppBar(
        leading: Icon(Icons.arrow_back),
        title: Text('App 簡單示例'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.playlist_play),
            tooltip: 'Air it',
            onPressed: (){},
          ),
          IconButton(
            icon: Icon(Icons.playlist_add),
            tooltip: 'Restitch it',
            onPressed: (){},
          ),
          IconButton(
            icon: Icon(Icons.playlist_add_check),
            tooltip: 'Repair it',
            onPressed: (){},
          ),
        ],
      ),
複製代碼

AppBar 加深學習 Sample 1

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

class AppBarBottomSample extends StatefulWidget {
  @override
  _AppBarBottomSampleState createState() => new _AppBarBottomSampleState();
}

class _AppBarBottomSampleState extends State<AppBarBottomSample> with SingleTickerProviderStateMixin {
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = new TabController(vsync: this, length: choices.length);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  void _nextPage(int delta) {
    final int newIndex = _tabController.index + delta;
    if (newIndex < 0 || newIndex >= _tabController.length)
      return;
    _tabController.animateTo(newIndex);
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: const Text('AppBar Bottom Widget'),
          leading: new IconButton(
            tooltip: 'Previous choice',
            icon: const Icon(Icons.arrow_back),
            onPressed: () { _nextPage(-1); },
          ),
          actions: <Widget>[
            new IconButton(
              icon: const Icon(Icons.arrow_forward),
              tooltip: 'Next choice',
              onPressed: () { _nextPage(1); },
            ),
          ],
          bottom: new PreferredSize(
            preferredSize: const Size.fromHeight(48.0),
            child: new Theme(
              data: Theme.of(context).copyWith(accentColor: Colors.white),
              child: new Container(
                height: 48.0,
                alignment: Alignment.center,
                child: new TabPageSelector(controller: _tabController),
              ),
            ),
          ),
        ),
        body: new TabBarView(
          controller: _tabController,
          children: choices.map((Choice choice) {
            return new Padding(
              padding: const EdgeInsets.all(16.0),
              child: new ChoiceCard(choice: choice),
            );
          }).toList(),
        ),
      ),
    );
  }
}

class Choice {
  const Choice({ this.title, this.icon });
  final String title;
  final IconData icon;
}

const List<Choice> choices = const <Choice>[
  const Choice(title: 'CAR', icon: Icons.directions_car),
  const Choice(title: 'BICYCLE', icon: Icons.directions_bike),
  const Choice(title: 'BOAT', icon: Icons.directions_boat),
  const Choice(title: 'BUS', icon: Icons.directions_bus),
  const Choice(title: 'TRAIN', icon: Icons.directions_railway),
  const Choice(title: 'WALK', icon: Icons.directions_walk),
];

class ChoiceCard extends StatelessWidget {
  const ChoiceCard({ Key key, this.choice }) : super(key: key);

  final Choice choice;

  @override
  Widget build(BuildContext context) {
    final TextStyle textStyle = Theme.of(context).textTheme.display1;
    return new Card(
      color: Colors.white,
      child: new Center(
        child: new Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            new Icon(choice.icon, size: 128.0, color: textStyle.color),
            new Text(choice.title, style: textStyle),
          ],
        ),
      ),
    );
  }
}

//程序入口
void main() {
  runApp(new AppBarBottomSample());
}
複製代碼

AppBar 加深學習 Sample 2

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

class TabbedAppBarSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new DefaultTabController(
        length: choices.length,
        child: new Scaffold(
          appBar: new AppBar(
            title: const Text('Tabbed AppBar'),
            bottom: new TabBar(
              isScrollable: true,
              tabs: choices.map((Choice choice) {
                return new Tab(
                  text: choice.title,
                  icon: new Icon(choice.icon),
                );
              }).toList(),
            ),
          ),
          body: new TabBarView(
            children: choices.map((Choice choice) {
              return new Padding(
                padding: const EdgeInsets.all(16.0),
                child: new ChoiceCard(choice: choice),
              );
            }).toList(),
          ),
        ),
      ),
    );
  }
}

class Choice {
  const Choice({ this.title, this.icon });
  final String title;
  final IconData icon;
}

const List<Choice> choices = const <Choice>[
  const Choice(title: 'CAR', icon: Icons.directions_car),
  const Choice(title: 'BICYCLE', icon: Icons.directions_bike),
  const Choice(title: 'BOAT', icon: Icons.directions_boat),
  const Choice(title: 'BUS', icon: Icons.directions_bus),
  const Choice(title: 'TRAIN', icon: Icons.directions_railway),
  const Choice(title: 'WALK', icon: Icons.directions_walk),
];

class ChoiceCard extends StatelessWidget {
  const ChoiceCard({ Key key, this.choice }) : super(key: key);

  final Choice choice;

  @override
  Widget build(BuildContext context) {
    final TextStyle textStyle = Theme.of(context).textTheme.display1;
    return new Card(
      color: Colors.white,
      child: new Center(
        child: new Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            new Icon(choice.icon, size: 128.0, color: textStyle.color),
            new Text(choice.title, style: textStyle),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(new TabbedAppBarSample());
}
複製代碼

底部導航條 BottomNavigationBar

底部導航條,能夠很容易地在tap之間切換和瀏覽頂級視圖

經常使用屬性

屬性名 類型 說明
currentIndex int 當前索引
fixedColor Color 選中按鈕的 Color 。不指定則使用系統主題 Color
iconSize double 按鈕圖形大小
items List<BottomNavigatorBarItem> 底部導航欄按鈕集。每一項是一個BottomNavigatorBarItem,包含icon圖標和title文本
onTap ValueChanged<int> 按下按鈕的回調事件。須要根據返回的索引設置當前索引

import 'package:flutter/material.dart';
void main()=>runApp(MaterialApp(
  home: HomePage(),
));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedIndex = 1;
  final _widgetOptions = [
    Text('Index 0: 最近'),
    Text('Index 1: 通信錄'),
    Text('Index 2: 發現'),
    Text('Index 3: 個人'),
  ];


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BottomNavigationBar Sample'),
      ),
      body: Center(
        child: _widgetOptions.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: BottomNavigationBar(items: [
        BottomNavigationBarItem(icon: Icon(Icons.history),title:Text('最近'),backgroundColor:Colors.deepPurple),
        BottomNavigationBarItem(icon: Icon(Icons.contact_phone),title:Text('通信錄'),backgroundColor:Colors.deepPurple),
        BottomNavigationBarItem(icon: Icon(Icons.find_in_page),title:Text('發現'),backgroundColor:Colors.deepPurple),
        BottomNavigationBarItem(icon: Icon(Icons.my_location),title:Text('個人'),backgroundColor:Colors.deepPurple),
      ],
        currentIndex: _selectedIndex,
        fixedColor: Colors.deepPurple,
        onTap: (index){
        setState(() {
          _selectedIndex = index;
        });
        },
      ),

    );
  }
}

複製代碼

選項卡 TabBar

TabBar 是一個顯示水平選項卡的 Material Design 組件,一般須要配套 Tab 選項組件及TabBarView 頁面視圖組件一塊兒使用。

經常使用屬性

屬性名 類型 說明
controller TabController 這個 widget 的選擇和動畫狀態
dragStartBehavior DragStartBehavior 肯定處理拖動開始行爲的方式
indicatorPadding EdgeInsetsGeometry 顯示在所選選項卡下方的線條的水平填充。對於 isScrollable 標籤欄,指定kTabLabelPadding 會將指示符與 Tab小部件的選項卡文本以及除最短Tab.text 值以外的全部文本對齊
indicator Decoration 定義所選選項卡指示器的外觀
indicatorColor Color 顯示在所選選項卡下方的線條 Color 。若是此參數爲 null ,則使用 Theme 的indicatorColor 屬性的值
indicatorSize TabBarIndicatorSize 定義如何計算選定選項卡指示符的大小
indicatorWeight double 顯示在所選選項卡下方的線條粗細。此參數的值必須大於零
isScrollable bool 此選項卡欄是否能夠水平滾動
labelColor Color 選中 Tab 的 Color
labelPadding TextStyle 填充添加到每一個選項卡標籤
onTap ValueChanged 點擊 TabBar 時調用的可選回調
preferredSize Size 高度取決於標籤是否同時包含圖標和文本的大小
tabs List 一般是兩個或多個 Tab 小部件的列表
unselectedLabelColor Color 未選定標籤標籤的 Color
unselectedLableStyle TextStyle 未選定標籤標籤的文本樣式

TabBar可用於在TabBarView中顯示的頁面之間導航。雖然TabBar是一個能夠出如今任何地方的普通widget,但它一般包含在應用程序的AppBar中。

經過 AndroidStudio 建立一個新項目,並用下面的代碼替換lib/main.dart的內容來嘗試運行一下。

簡單示例

import 'package:flutter/material.dart';

void main() =>runApp(MaterialApp(home:  HomePage(),));

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: choices.length,
        child: Scaffold(
          appBar: AppBar(
            title: Text('TabBar 示例'),
            bottom: new TabBar(
              //tab 支持滑動
                isScrollable: true,
                tabs: choices.map((choice){ //這裏至關於 遍歷
                  print("遍歷:→ "+choice.title);
                  return Tab(
                    text: choice.title,
                    icon: new Icon(choice.icon),
                  );
                }).toList()
            ),
          ),
          body: TabBarView(children: choices.map((item){
            return new Tab(
              text: item.title,
              icon: Icon(item.icon),
            );
          }).toList()),
        ),
    );
  }
}

class Choice {
  const Choice({ this.title, this.icon });
  final String title;
  final IconData icon;
}

const List<Choice> choices = const <Choice>[
  const Choice(title: 'CAR', icon: Icons.directions_car),
  const Choice(title: 'BICYCLE', icon: Icons.directions_bike),
  const Choice(title: 'BOAT', icon: Icons.directions_boat),
  const Choice(title: 'BUS', icon: Icons.directions_bus),
  const Choice(title: 'TRAIN', icon: Icons.directions_railway),
  const Choice(title: 'WALK', icon: Icons.directions_walk),
];

複製代碼

TabBarView

顯示與當前選中的選項卡相對應的頁面視圖。一般和TabBar一塊兒使用

經常使用屬性

屬性名 類型 說明
children List 每一個標籤的小部件
controller TabController 此小部件的選擇和動畫狀態
dragStartBebavior DragStartBehavior 肯定處理拖動開始行爲的方式
physics ScroolPhysics 頁面視圖應如何響應用戶輸入

簡單使用

import 'package:flutter/material.dart';
import 'package:flutter/src/scheduler/ticker.dart';

void main() =>runApp(MaterialApp(home:  HomePage(),));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin{
  TabController _TabController;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _TabController =  TabController(vsync: this,length: choices.length);
  }
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _TabController.dispose();
  }

  void _nextPage(int delta){
   final int newIndex =  _TabController.index + delta;
   if (newIndex < 0 || newIndex >= _TabController.length)
     return;
   _TabController.animateTo(newIndex);
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('TabBarView 示例'),
            
            bottom:PreferredSize(child: Theme( data: Theme.of(context).copyWith(accentColor: Colors.white),
                child: Container(
                  height: 50.0,
                  alignment: Alignment.center,
                  child: TabPageSelector(controller: _TabController,),
                )), preferredSize: Size.fromHeight(50.0)) ,
        ),
        body: DefaultTabController(length: choices.length, child:  TabBarView(
            controller: _TabController,
            children: choices.map((item){
          return new Tab(
            text: item.title,
            icon: Icon(item.icon),
          );
        }).toList()),)
      ),
      
    );
  }
}

class Choice {
  const Choice({ this.title, this.icon });
  final String title;
  final IconData icon;
}

const List<Choice> choices = const <Choice>[
  const Choice(title: 'CAR', icon: Icons.directions_car),
  const Choice(title: 'BICYCLE', icon: Icons.directions_bike),
  const Choice(title: 'BOAT', icon: Icons.directions_boat),
  const Choice(title: 'BUS', icon: Icons.directions_bus),
  const Choice(title: 'TRAIN', icon: Icons.directions_railway),
  const Choice(title: 'WALK', icon: Icons.directions_walk),
];

複製代碼

MaterialApp

MaterialApp 表明使用 Material Design 風格的應用,裏面包含了其餘所需的基本控件。官方提供的示例 demo 就是從 MaterialApp 這個主組件開始的。

經常使用屬性

屬性名 類型 說明
title String 應用程序的標題。該標題出如今如下位置:Android:任務管理器的程序快照上; IOS:程序切換管理器中
theme ThemeData 定義應用所使用的主題 Color ,能夠指定主題中每一個控件的 Color
color Color 應用的主要 Color 值,即 primary color
home Widget 用來定義當前應用打開時所顯示的界面
routes Map<String, WidgetBuilder> 定義應用中頁面跳轉規則
initialRoute String 初始化路由
onGenerateRoute RouteFactory 路由回調函數。當經過Navigator.of(context).pushNamed跳轉路由的時候,在routes查找不到時,會調用該方法
onLocaleChanged - 當系統修改語言的時候,會觸發這個回調
navigatorObservers List<NavigatorObserver> 導航觀察器
debugShowMaterialGrid bool 是否顯示佈局網格,用來調試UI的工具
showPerformanceOverlay bool 顯示性能標籤

設置主頁

使用 home 屬性設置應用的主頁,及整個應用的主組件。

路由處理

routes 對象是一個 Map<String, WidgetBuilder> 。當使用 Navigator.pushNamed 來跳轉路由的時候,經過 routes 查找路由名字,而後使用對應的 WidgetBuilder 來構造一個帶有頁面切換動畫的 MaterialPageRoute 。若是應用只有一個界面,則不用設置整個屬性,使用 home 便可。

自定義主題

應用程序的主題,各類定製的 Color 均可以設置,用於程序主題切換

WidgetsApp

一個方便的類,它封裝了應用程序一般須要的一些widget

抽屜組件 Drawe

Drawer能夠實現相似抽屜拉入推出的效果,一般與ListView組合使用。

經常使用屬性

屬性名 類型 默認值 說明
child Widget - Drawer 的 child 能夠放置任意可顯示的組件
elevation double 16 陰影尺寸

Drawer能夠添加頭部效果:

  • DrawerHeader:展現基本信息
  • UserAccountsDrawerHeader:展現用戶頭像、用戶名、Email等信息

DrawerHeader經常使用屬性

屬性名 類型 說明
decoration Decoration header區域的decoration,一般用來設置背景 Color 或背景圖片
curve Curve 若是decoration發生了變化,則會使用curve設置的變化曲線和duration設置的動畫時間來作一個動畫效果
child Widget Header裏面所顯示的內容控件
padding EdgeInsetsGeometry Header裏面內容控件的padding值,若是child爲null,該值無效
margin EdgeInsetsGeometry Header四周的間隙

UserAccountsDrawerHeader經常使用屬性

屬性名 類型 說明
margin EdgeInsetsGeometry Header四周的間隙
decoration Decoration header區域的decoration,一般用來設置背景 Color 或背景圖片
currentAccountPicture Widget 用來設置當前用戶的頭像
otherAccountsPicture Widget 用來設置當前用戶其餘帳號的頭像
accountName Widget 當前用戶的名字
accountEmail Widget 當前用戶的Email
onDetailsPressed VoidCallback 當accountName或者accountEmail被點擊的時候所觸發的回調函數,能夠用來顯示其餘額外的信息

簡單演示

import 'package:flutter/material.dart';

void main ()=> runApp(MaterialApp(
  home: DrawerWidget(),
));

class DrawerWidget extends StatefulWidget {
  @override
  _DrawerWidgetState createState() => _DrawerWidgetState();
}

class _DrawerWidgetState extends State<DrawerWidget> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('drawer 示例'),
      ),
      drawer: BuildDrawer(),
    );
  }
}

class BuildDrawer extends StatefulWidget {
  @override
  _BuildDrawerState createState() => _BuildDrawerState();
}

class _BuildDrawerState extends State<BuildDrawer> {
  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: ListView(
        children: <Widget>[
          UserAccountsDrawerHeader(
            currentAccountPicture: CircleAvatar(
              backgroundImage: NetworkImage(
                  'https://randomuser.me/api/portraits/women/17.jpg'),
            ),
            accountName: Text('Damon'),
            accountEmail: Text('3262663349@qq.com'),
            otherAccountsPictures: <Widget>[
              Icon(Icons.camera),
            ],
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('assets/images/xinqiu.jpg'),
                fit: BoxFit.fill,
              ),
            ),
          ),
          ListTile(
            leading: Icon(Icons.payment),
            title: Text('會員特權'),
          ),
          ListTile(
            leading: Icon(Icons.payment),
            title: Text('會員特權'),
          ),
          ListTile(
            leading: Icon(Icons.payment),
            title: Text('會員特權'),
          ),
          AboutListTile(
            icon: Icon(Icons.error),
            child: Text('關於'),
            applicationName: '哈哈'
            ,applicationVersion: '1.0',
          )
        ],
      ),
    );
  }
}


複製代碼

按鈕

RaisedButton

簡介

Meaterial Design 中的 Botton , 一個凸起的材質矩形按鈕。

經常使用屬性

屬性名 類型 說明
animationDuration Duration 定義形狀和高程的動畫更改的持續時間
child Widget 按鈕的標籤
clipBehavior Clip 根據此選項,內容將被剪裁(或不剪輯)
color Color 按鈕的填充 Color ,由其材料顯示,同時處於默認(未按下,已啓用)狀態
colorBrightness Brightness 用於此按鈕的主題亮度
disabledColor Color 禁用按鈕時按鈕的填充 Color
disabledTextColor Color 禁用按鈕時用於此按鈕文本的 Color
elevation double 將此按鈕相對於其父級放置的z座標
enabled bool 是啓用仍是禁用按鈕
height double 按鈕的垂直範圍
highightColor Color 按鈕的InkWell的高亮 Color
highlightElevation double 啓用並按下按鈕時按鈕的材質相對於其父級的高程
materialTapTargetSize MaterialTapTargetSize 配置點擊目標的最小尺寸
minWidth double 按鈕佔據的最小水平範圍
onHighlightChanged ValueChanged 由底層 InkWell 小部件的InkWell.onHighlightChanged 回調調用。
onPressed VoidCallback 點擊或以其餘方式激活按鈕時調用的回調
padding EdgeInsetsGeometry 按鈕的孩子的內部填充
shape ShapeBorder 按鈕材質的形狀
splashColor Clor 按鈕 InkWell 的閃爍 Color
textColor Color 用於此按鈕文本的 Color 。
textTheme ButtonTextTheme 定義按鈕的 Color ,以及按鈕的最小尺寸,內部填充和形狀的默認值

簡單示例

// This sample shows how to render a disabled RaisedButton, an enabled RaisedButton
// and lastly a RaisedButton with gradient background.

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: 'Flutter Code Sample for material.RaisedButton',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyStatelessWidget(),
    );
  }
}

class MyStatelessWidget extends StatelessWidget {
  MyStatelessWidget({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            RaisedButton(
              onPressed: null,
              child: const Text('Disabled Button'),
            ),
            RaisedButton(
              onPressed: () {},
              child: const Text('Enabled Button'),
            ),
            RaisedButton(
              onPressed: () {},
              textColor: Colors.white,
              padding: const EdgeInsets.all(0.0),
              child: Container(
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: <Color>[Colors.red, Colors.green, Colors.blue],
                  ),
                ),
                padding: const EdgeInsets.all(10.0),
                child: Text('Gradient Button'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
複製代碼

FloationgActionButton

簡介

一個圓形圖標按鈕,它懸停在內容之上,以展現應用程序中的主要動做。FloatingActionButton 一般用於 Scaffold.floatingActionButton 字段。

經常使用屬性

屬性名 類型 說明
backgroudColor Color 填充按鈕時使用的 Color
child Widget 樹中此小部件下方的小部件
clipBehavior Clip 根據此選項,內容將被剪裁(或不剪輯)。
disableElevation double 禁用按鈕時放置此按鈕的 z 座標( onPressed 爲 null)
elevation double 用於將此按鈕與其父按鈕相關聯的z座標
foregroudColor Color 默認圖標和文本 Color 。
heroTag Object 要應用於按鈕的Hero小部件的標記
highlightElevation double 當用戶觸摸按鈕時,將此按鈕相對於其父按鈕放置的z座標
isExtended bool 若是這是一個「擴展」浮動操做按鈕,則爲 True
materialTapTargetSize MaterialTapTargetSize 配置點擊目標的最小尺寸
mini bool 控制此按鈕的大小
onPressed VoidCallback 點擊或以其餘方式激活按鈕時調用的回調
shape ShapeBorder 按鈕材質的形狀
tooltip String 描述按下按鈕時將發生的操做的文本

簡單示例

home: Scaffold(
        appBar: AppBar(
          title: Text('FloatingActionButton 示例'),
        ),
        body: Center(child: Text('FloatingActionButton 示例'),),
        floatingActionButton: FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: (){}),
        
      ),
複製代碼

FlatButton

簡介

一個扁平的 Material 按鈕

經常使用屬性

屬性名 類型 說明
animationDuration Duration 定義形狀和高程的動畫更改的持續時間
child Widget 按鈕的標籤
chlipBebavior Clip 根據此選項,內容將被剪裁(或不剪輯)
color Color 按鈕的填充 Color ,由其材料顯示,同時處於默認(未按下,已啓用)狀態
colorBrightness Brightness 用於此按鈕的主題亮度
disabledColor Color 禁用按鈕時按鈕的填充 Color
disableElevation double 未啓用按鈕時按鈕的材質相對於其父級的高程
disableTextColor Color 禁用按鈕時用於此按鈕文本的 Color Color
elevation double 將此按鈕相對於其父級放置的z座標。
enable bool 是啓用仍是禁用按鈕
height double 按鈕的垂直範圍
highlightColor Color 按鈕的 InkWell 的高亮 Color
highlightElevation double 啓用並按下按鈕時按鈕的材質相對於其父級的高程。
materialTapTargetSize MaterialTapTargetSize 配置點擊目標的最小尺寸
minWidth double 按鈕佔據的最小水平範圍。
onHighlightChanged ValueChanged 由底層 InkWell 小部件的InkWell.onHighlightChanged 回調調用
onPressed VoidCallback 點擊或以其餘方式激活按鈕時調用的回調
padding EdgeInsetsGeometry 點擊或以其餘方式激活按鈕時調用的回調。
shape ShapeBorder 按鈕材質的形狀。
splashColor Color 按鈕 InkWell 的閃爍 Color
textColor Color 用於此按鈕文本的 Color 。
textTheme ButtonTextTheme 定義按鈕的 Color ,以及按鈕的最小尺寸,內部填充和形狀的默認值

簡單示例

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('FlatButton'),
        ),
        body: Center(
          child: Text('FlatButton'),
        ),
        floatingActionButton: FlatButton(
          onPressed: () {},
          child: Text(
            'FlatButton',
            style: TextStyle(color: Colors.white),
          ),
          color: Colors.deepPurple,
        ),
      ),
    ));

複製代碼

IconButton

簡介

一個 Material 圖標按鈕,點擊時會有水波動畫。

屬性介紹

屬性名 類型 說明
alignment AlignmentGeometry 定義圖標在 IconButton 中的定位方式
color Color 若是啓用了圖標,則用於按鈕內圖標的 Color 。默認狀況下將其留給圖標小部件
disableColor Color 若是圖標被禁用,則用於按鈕內圖標的 Color 。默認爲當前主題的 ThemeData.disabledColor 。
highlightColor Color 按鈕處於向下(按下)狀態時按鈕的輔助 Color 。 高亮 Color 表示爲覆蓋在按鈕 Color (若是有)上的純色。 若是突出顯示 Color 具備透明度,則將顯示按鈕 Color 。 按住按鈕時,突出顯示會快速消失。
icon Widget 要在按鈕內顯示的圖標
iconSize double 按鈕內圖標的大小。
onPressed VoidCallback 按鈕的回調
padding EdgeInsetsGeometry 按鈕圖標周圍的填充。整個填充圖標將對輸入手勢作出反應
splashColor Color 按鈕處於向下(按下)狀態時按鈕的主要 Color 。 飛濺表示爲突出顯示在 highlightColor 疊加層上方的圓形疊加層。 初始疊加層的中心點與用戶觸摸事件的生命點相匹配。 若是觸摸持續足夠長的時間,飛濺疊加將擴展以填充按鈕區域。 若是初始 Color 具備透明度,則突出顯示和按鈕 Color 將顯示
tooltip String 描述按下按鈕時將發生的操做的文本

簡單示例

import 'package:flutter/material.dart';

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

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text('IconButton 示例'),
          actions: <Widget>[
            IconButton(icon: Icon(Icons.home), onPressed: (){}),
            IconButton(icon: Icon(Icons.radio), onPressed: (){}),
            IconButton(icon: Icon(Icons.verified_user), onPressed: (){}),
            IconButton(icon: Icon(Icons.voice_chat), onPressed: (){}),
            IconButton(icon: Icon(Icons.video_call), onPressed: (){}),
          ],
        ),
      ),
    );
  }
}


複製代碼

PopupMenuButton

簡介

當菜單隱藏式,點擊或調用 onSelected 時顯示一個彈出式菜單列表

經常使用屬性

屬性名 類型 說明
child Widget 若是提供,則用於此按鈕的小部件。
elevation double 打開時放置菜單的z座標。這能夠控制菜單下方陰影的大小
icon Icon 若是提供,則用於此按鈕的圖標
initialValue T 菜單項的值(若是有),在菜單打開時應突出顯示。
offset Offset 應用於彈出菜單按鈕的偏移量
onCanceled PopupMenuCanceled 當用戶在不選擇項目的狀況下關閉彈出菜單時調用
onSelected PopupMenuItemSelected 當用戶今後按鈕建立的彈出菜單中選擇一個值時調用
padding EdgeInsetsGeometry 默認狀況下,匹配 IconButton 的 8 dps填充。在某些狀況下,特別是在此按鈕做爲列表項的尾隨元素出現的狀況下,可以將填充設置爲零是有用的。
tooltip String 描述按下按鈕時將發生的操做的文本
itemBuilder PopupMenuItemBuilder 按下按鈕時調用以建立要在菜單中顯示的項目。

簡單示例

import 'package:flutter/material.dart';

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

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text('PopupMenuButton 示例'),
          actions: <Widget>[
            IconButton(icon: Icon(Icons.home), onPressed: () {}),
            IconButton(icon: Icon(Icons.radio), onPressed: () {}),
            IconButton(icon: Icon(Icons.verified_user), onPressed: () {}),
            IconButton(icon: Icon(Icons.voice_chat), onPressed: () {}),
            IconButton(icon: Icon(Icons.video_call), onPressed: () {}),
            PopupMenuButton(
                itemBuilder: (context) => [
                      PopupMenuItem(child: Text('popupMenuItem ')),
                      PopupMenuItem(child: Text('popupMenuItem 1')),
                      PopupMenuItem(child: Text('popupMenuItem 2')),
                      PopupMenuItem(child: Text('popupMenuItem 3')),
                    ]
              ,
              onCanceled: (){
                  print('onCenten');
              },
            ),
          ],
        ),
      ),
    );
  }
}

複製代碼

ButtonBar

簡介

水平排列的按鈕組

經常使用屬性

屬性名 類型 說明
alignment MainAxisAlignment 如何將孩子放在水平軸上
children List 按鈕水平排列
mainAxisSize MainAxisSize 有多少水平空間可供選擇。請參見Row.mainAxisSize

簡單示例

ButtonBar(
        children: <Widget>[
          Text('測試'),
          Text('測試 2'),
          Icon(Icons.video_call,color: Color(0xffff0000),),
          Icon(Icons.voice_chat,color: Color(0xffff0000),),
          Icon(Icons.wallpaper,color: Color(0xffff0000),),
        ],
      ),
複製代碼

輸入框和選擇框

TextField

簡介

一個文本輸入框

經常使用屬性

屬性名 類型 說明
aotocorrect bool 是否啓用自動更正
autofocus bool 若是沒有其餘內容已經集中,這個文本字段是否應該集中注意力
buildCounter InputCounterWidgetBuilder 生成自定義InputDecorator.counter 小部件的回調
controller TextEditingController 繪製光標時使用的 Color 。
cursorColor Color 繪製光標時使用的 Color
cursorRadius Radius 光標的角應該是多圓的
cursorWidth double 光標的厚度。
decoration InputDecoration 在文本字段周圍顯示的裝飾。
dragStartBehavior DragStartBehavior 肯定處理拖動開始行爲的方式。
enable bool 若是爲 false,則文本字段爲「禁用」:它忽略點擊而且其裝飾以灰 Color 呈現。
enableInteractiveSelection bool 若是爲 true,則長按此TextField 將選擇文本並顯示剪切/複製/粘貼菜單,而且點擊將移動文本插入符號。
focusNode FocusNode 定義此窗口小部件的鍵盤焦點
inputFormatters List 可選的輸入驗證和格式覆蓋。
keyboardAppearance Brightness 鍵盤的外觀
keyboardType TextInputType 用於編輯文本的鍵盤類型
maxLength int 若是爲 true,則阻止該字段容許超過 maxLength 個字符
maxLines int 文本要跨越的最大行數,必要時包裝
obsureText bool 是否隱藏正在編輯的文本(例如,用於密碼)。
onCanged ValueChanged 當用戶啓動對 TextField 值的更改時調用:當他們插入或刪除文本時。
onEditingComplete VoidCallback 當用戶提交可編輯內容時調用(例如,用戶按下鍵盤上的「完成」按鈕)。
onSubmitted ValueChanged 當用戶指示他們已完成編輯字段中的文本時調用
onTap GestureTapCallback 當用戶點擊此文本字段時調用
scrollPadding EdgeInsets 當 Textfield 滾動到視圖中時,將填充配置到Scrollable 周圍的邊緣。
selectionEnabled bool 若是基於enableInteractiveSelection和obscureText 的值啓用了交互式選擇,則爲 True。
style TextStyle 用於正在編輯的文本的樣式。
textAlign TextAlign 文本應如何水平對齊
textCapitalization TextCapitalization 配置平臺鍵盤如何選擇大寫或小寫鍵盤。
textDirection TextDirection 文本的方向性
textInputAction TextInputAction 用於鍵盤的操做按鈕類型

簡單示例

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: TextFieldPage(),
    ));

class TextFieldPage extends StatelessWidget {
  Widget buildTextField(TextEditingController controller) {
    return TextField(
      controller: controller,
      maxLength: 30,
      //最大長度,設置此項會讓TextField右下角有一個輸入數量的統計字符串
      maxLines: 1,
      //最大行數
      autocorrect: true,
      //是否自動更正
      autofocus: true,
      //是否自動對焦
      obscureText: true,
      //是不是密碼
      textAlign: TextAlign.start,
      //文本對齊方式
      style: TextStyle(fontSize: 30.0, color: Colors.blue),
      //輸入文本的樣式
// inputFormatters: [WhitelistingTextInputFormatter.digitsOnly,BlacklistingTextInputFormatter.singleLineFormatter],
      //容許的輸入格式
      onChanged: (text) {
        //內容改變的回調
        print('change $text');
      },
      onSubmitted: (text) {
        //內容提交(按回車)的回調
        print('submit $text');
      },
      enabled: true, //是否禁用
    );
  }

  @override
  Widget build(BuildContext context) {
    final controller = TextEditingController();
    controller.addListener(() {
      print('input ${controller.text}');
    });
    return Scaffold(
      appBar: AppBar(
        title: Text('TextField'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: buildTextField(controller),
      ),
    );
  }
}

複製代碼

Checkbox

簡介

複選框,容許用戶從一組中選擇多個選項。

經常使用屬性

屬性名 類型 說明
activeColor Color 選中此複選框時要使用的 Color
checkColor Color 選中此複選框時用於檢查圖標的 Color
tristate bool 若是爲true,則複選框的值能夠爲true,false或null。
materialTapTargetSize MaterialTapTargetSize 配置點擊目標的最小尺寸
onChanged ValueChanged 當複選框的值應該更改時調用
values bool 是否選中此複選框

簡單示例

import 'package:flutter/material.dart';

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

class CheckboxPage extends StatefulWidget {
  @override
  _CheckboxPageState createState() => _CheckboxPageState();
}

class _CheckboxPageState extends State<CheckboxPage> {

  bool _values = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Checkbox 示例'),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            Checkbox(
              //選中的背景色
              activeColor: Colors.red,
              //選中的 勾 的顏色
              checkColor: Colors.white,
                materialTapTargetSize: MaterialTapTargetSize.padded,
                value: _values,
                onChanged: (isSelect) {
                setState(() {
                  _values = isSelect;
                });
                  print(isSelect);
                })
          ],
        ),
      )
    );
  }
}

複製代碼

Radio

簡介

單選框,容許用戶從一組中選擇一個選項。

經常使用屬性

屬性名 類型 說明
activeColor Color 選中的背景色
groupValue T 此組單選按鈕的當前選定值
materialTapTargetSize MaterialTapTargetSize 配置點擊目標的最小尺寸。
onCanged ValueChanged 當用戶選擇此單選按鈕時調用
value T 此單選按鈕表示的值

簡單示例

import 'package:flutter/material.dart';

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

class CheckboxPage extends StatefulWidget {
  @override
  _CheckboxPageState createState() => _CheckboxPageState();
}

class _CheckboxPageState extends State<CheckboxPage> {

  var groupValue = 1;
  updateGroupValue(t){
    setState(() {
      groupValue = t;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Checkbox 示例'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Radio(value: 0, groupValue: 0, onChanged: null),//onChanged爲null表示按鈕不可用
              new Radio(
                  value: 1,
                  groupValue: groupValue,//當value和groupValue一致的時候則選中
                  activeColor: Colors.red,
                  onChanged: (T){
                    updateGroupValue(T);
                  }
              ),
              new Radio(
                  value: 2,
                  groupValue: groupValue,
                  onChanged: (T){
                    updateGroupValue(T);
                  }
              ),
              new Radio(
                  value: 3,
                  groupValue: groupValue,
                  onChanged: (T){
                    updateGroupValue(T);
                  }
              ),
              new Radio(
                  value: 4,
                  groupValue: groupValue,
                  onChanged: (T){
                    updateGroupValue(T);
                  }
              ),
              new Radio(
                  value: 5,
                  groupValue: groupValue,
                  onChanged: (T){
                    updateGroupValue(T);
                  }
              ),
              new Radio(
                  value: 6,
                  groupValue: groupValue,
                  onChanged: (T){
                    updateGroupValue(T);
                  }
              ),

            ],
          ),
        )
    );
  }
}

複製代碼

Switch

簡介

On / off 用於切換一個單一狀態

經常使用屬性

屬性名 類型 說明
activeColor Color 這個顏色表明選擇時的背景色
groupValue T 此組單選按鈕的當前選定值
materialTapTargetSize MaterialTapTargetSize 配置點擊目標的最小尺寸
onChanged ValueChanged 當用戶選擇此單選按鈕時調用
value T 此單選按鈕表示的值

簡單示例

import 'package:flutter/material.dart';

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

class SwitchPage extends StatefulWidget {
  @override
  _SwitchPageState createState() => _SwitchPageState();
}

class _SwitchPageState extends State<SwitchPage> {
  var groupValue = 1;
  var _value = true;

  updateGroupValue(t) {
    setState(() {
      groupValue = t;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Switch 示例'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Switch(
                  activeColor: Colors.deepPurple,
                  value: _value,
                  onChanged: (select) {
                    setState(() {
                      _value = select;
                    });
                  }),
              Switch(
                  value: _value,
                  onChanged: (select) {
                    setState(() {
                      _value = select;
                    });
                  }),
            ],
          ),
        ));
  }
}

複製代碼

Slider

簡介

滑塊,容許用戶經過滑動滑塊來從一系列值中選擇。

經常使用屬性

屬性名 類型 說明
activeColor Color 用於滑塊軌道中活動部分的顏色
divisions int 離散分數的數量
inactiveColor Color 滑動軌道未滑動的顏色值
label String 滑塊處於活動狀態時顯示在滑塊上方的標籤
max double 用戶能夠選擇的最大值
min double 用於能夠選擇的最小值
onChanged ValueChanged 滑動監聽的值
onChangeEnd ValueChanged 滑動結束
onChangeStart ValueChanged 滑動開始
semanticFormatterCallback SemanticFormatterCallback 回調用於從滑塊值建立語義值
value double 此滑塊的當前選定值

簡單示例

import 'package:flutter/material.dart';
import 'dart:math' as math;
void main()=> runApp(MaterialApp(home: SliderPage()));
class SliderPage extends StatefulWidget {
  @override
  _SliderPageState createState() => _SliderPageState();
}
Path _triangle(double size, Offset thumbCenter, {bool invert = false}) {
  final Path thumbPath = Path();
  final double height = math.sqrt(3.0) / 2.0;
  final double halfSide = size / 2.0;
  final double centerHeight = size * height / 3.0;
  final double sign = invert ? -1.0 : 1.0;
  thumbPath.moveTo(thumbCenter.dx - halfSide, thumbCenter.dy + sign * centerHeight);
  thumbPath.lineTo(thumbCenter.dx, thumbCenter.dy - 2.0 * sign * centerHeight);
  thumbPath.lineTo(thumbCenter.dx + halfSide, thumbCenter.dy + sign * centerHeight);
  thumbPath.close();
  return thumbPath;
}
class _SliderPageState extends State<SliderPage> {
  double _value = 25.0;
  double _discreteValue = 20.0;

  _upDataValue(double){
    setState(() {
      _value = double;
    });
  }

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          SliderTheme(
            data: theme.sliderTheme.copyWith(
              activeTrackColor: Colors.deepPurple,
              inactiveTrackColor: Colors.black26,
              activeTickMarkColor: Colors.white70,
              inactiveTickMarkColor: Colors.black,
              overlayColor: Colors.black12,
              thumbColor: Colors.deepPurple,
              valueIndicatorColor: Colors.deepPurpleAccent,
              thumbShape: _CustomThumbShape(),
              valueIndicatorShape: _CustomValueIndicatorShape(),
              valueIndicatorTextStyle: theme.accentTextTheme.body2.copyWith(color: Colors.black87),
            ),
            child: Slider(
              value: _discreteValue,
              min: 0.0,
              max: 200.0,
              divisions: 5,
              semanticFormatterCallback: (double value) => value.round().toString(),
              label: '${_discreteValue.round()}',
              onChanged: (double value) {
                setState(() {
                  _discreteValue = value;
                });
              },
            ),
          ),
          const Text('Discrete with Custom Theme'),
        ],
      ),
    );
  }
}
class _CustomThumbShape extends SliderComponentShape {
  static const double _thumbSize = 4.0;
  static const double _disabledThumbSize = 3.0;

  @override
  Size getPreferredSize(bool isEnabled, bool isDiscrete) {
    return isEnabled ? const Size.fromRadius(_thumbSize) : const Size.fromRadius(_disabledThumbSize);
  }

  static final Animatable<double> sizeTween = Tween<double>(
    begin: _disabledThumbSize,
    end: _thumbSize,
  );

  @override
  void paint(
      PaintingContext context,
      Offset thumbCenter, {
        Animation<double> activationAnimation,
        Animation<double> enableAnimation,
        bool isDiscrete,
        TextPainter labelPainter,
        RenderBox parentBox,
        SliderThemeData sliderTheme,
        TextDirection textDirection,
        double value,
      }) {
    final Canvas canvas = context.canvas;
    final ColorTween colorTween = ColorTween(
      begin: sliderTheme.disabledThumbColor,
      end: sliderTheme.thumbColor,
    );
    final double size = _thumbSize * sizeTween.evaluate(enableAnimation);
    final Path thumbPath = _triangle(size, thumbCenter);
    canvas.drawPath(thumbPath, Paint()..color = colorTween.evaluate(enableAnimation));
  }
}

class _CustomValueIndicatorShape extends SliderComponentShape {
  static const double _indicatorSize = 4.0;
  static const double _disabledIndicatorSize = 3.0;
  static const double _slideUpHeight = 40.0;

  @override
  Size getPreferredSize(bool isEnabled, bool isDiscrete) {
    return Size.fromRadius(isEnabled ? _indicatorSize : _disabledIndicatorSize);
  }

  static final Animatable<double> sizeTween = Tween<double>(
    begin: _disabledIndicatorSize,
    end: _indicatorSize,
  );

  @override
  void paint(
      PaintingContext context,
      Offset thumbCenter, {
        Animation<double> activationAnimation,
        Animation<double> enableAnimation,
        bool isDiscrete,
        TextPainter labelPainter,
        RenderBox parentBox,
        SliderThemeData sliderTheme,
        TextDirection textDirection,
        double value,
      }) {
    final Canvas canvas = context.canvas;
    final ColorTween enableColor = ColorTween(
      begin: sliderTheme.disabledThumbColor,
      end: sliderTheme.valueIndicatorColor,
    );
    final Tween<double> slideUpTween = Tween<double>(
      begin: 0.0,
      end: _slideUpHeight,
    );
    final double size = _indicatorSize * sizeTween.evaluate(enableAnimation);
    final Offset slideUpOffset = Offset(0.0, -slideUpTween.evaluate(activationAnimation));
    final Path thumbPath = _triangle(
      size,
      thumbCenter + slideUpOffset,
      invert: true,
    );
    final Color paintColor = enableColor.evaluate(enableAnimation).withAlpha((255.0 * activationAnimation.value).round());
    canvas.drawPath(
      thumbPath,
      Paint()..color = paintColor,
    );
    canvas.drawLine(
        thumbCenter,
        thumbCenter + slideUpOffset,
        Paint()
          ..color = paintColor
          ..style = PaintingStyle.stroke
          ..strokeWidth = 2.0);
    labelPainter.paint(canvas, thumbCenter + slideUpOffset + Offset(-labelPainter.width / 2.0, -labelPainter.height - 4.0));
  }
}
複製代碼

Date & Time Pickers

簡介

日期&時間選擇

簡單示例

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  color: Colors.white,
      home: DatePickerDemo(),
    ));

class DatePickerDemo extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _DatePickerDemo();
}

class _DatePickerDemo extends State<DatePickerDemo> {
  _showDataPicker() async {
    Locale myLocale = Localizations.localeOf(context);
    var picker = await showDatePicker(
        context: context,
        initialDate: DateTime.now(),
        firstDate: DateTime(2016),
        lastDate: DateTime(2020),
        locale: myLocale);
    setState(() {
      _time = picker.toString();
    });
  }

  _showTimePicker() async {
    var picker =
        await showTimePicker(context: context, initialTime: TimeOfDay.now());
    setState(() {
      _time = picker.toString();
    });
  }

  var _time;

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Text(_time == null ? '選擇日期' : _time),
          onPressed: () => _showDataPicker(),
        ),
        RaisedButton(
          child: Text(_time == null ? '選擇時間' : _time),
          onPressed: () => _showTimePicker(),
        ),
      ],
    );
  }
}

複製代碼

對話框、Alert 、Panel

SimpleDialog

簡介

簡單對話框能夠顯示附加的提示或操做

經常使用屬性

屬性名 類型 說明
backgroundColor Color 此對話框表面的背景顏色
children List 對話框的(可選)內容顯示在標題下方的SingleChildScrollView 中
contentPadding EdgeInsetsGeometry 填充內容。
elevation double 對話框的座標
semanticLable String 可訪問性框架用於在打開和關閉對話框時通知屏幕轉換的對話框的語義標籤
shape ShapeBorder 此對話框邊框的形狀
title Widget 對話框的(可選)標題在對話框頂部以大字體顯示
titlePadding EdgeInsetsGeometry 在標題周圍填充。

簡單示例

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

void main(){
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  _State createState() => new _State();
}

enum Answers{YES,NO,MAYBE}

class _State extends State<MyApp>{

  String _value = '';

  void _setValue(String value) => setState(() => _value = value);

  Future _askUser() async {
    switch(
    await showDialog(
        context: context,
        child: new SimpleDialog(
          title: new Text('測試 SimpleDialog'),
          semanticLabel: '---',
          children: <Widget>[
            new SimpleDialogOption(child: new Text('Yes!!!'),onPressed: (){Navigator.pop(context, Answers.YES);},),
            new SimpleDialogOption(child: new Text('NO :('),onPressed: (){Navigator.pop(context, Answers.NO);},),
            new SimpleDialogOption(child: new Text('Maybe :|'),onPressed: (){Navigator.pop(context, Answers.MAYBE);},),
          ],
        )
    )
    ) {
      case Answers.YES:
        _setValue('Yes');
        break;
      case Answers.NO:
        _setValue('No');
        break;
      case Answers.MAYBE:
        _setValue('Maybe');
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Name YK'),
        backgroundColor: Colors.red,
      ),
      body: new Container(
        padding: new EdgeInsets.all(32.0),
        child: new Center(
          child: new Column(
            children: <Widget>[
              new Text(_value),
              new RaisedButton(onPressed: _askUser, child: new Text('Click me'),)
            ],
          ),
        ),
      ),
    );
  }
}
複製代碼

AlertDialog

簡介

一個會中斷用戶操做的對話款,須要用戶確認

經常使用屬性

屬性名 類型 說明
actions List 顯示在對話框底部的(可選)操做集
backgroundColor Color 此對話框表面的背景顏色
content Widget 對話框的(可選)內容以較淺的字體顯示在對話框的中央
contentPadding EdgeInsetsGeometry 填充內容
contentTextStyle TextStyle 此 AlertDialog 內容中文本的樣式
elevation double 此對話框的z座標
semanticLable String 可訪問性框架用於在打開和關閉對話框時通知屏幕轉換的對話框的語義標籤。
title Widget 對話框的(可選)標題在對話框頂部以大字體顯示。
titlePadding EdgeInsetsGeometry 在標題周圍填充
titleTextStyle TextStyle 此 AlertDialog 標題中文本的樣式
shape ShapeBorder 此對話框邊框的形狀。

簡單示例

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

void main(){
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  _State createState() => new _State();
}

//State is information of the application that can change over time or when some actions are taken.
class _State extends State<MyApp>{

  Future _showAlert(BuildContext context, String message) async {
    return showDialog(
        context: context,
        child: new AlertDialog(
          title: new Text(message),
          content: Text(message,style: TextStyle(fontSize: 14.0),),
          actions: <Widget>[
            new FlatButton(onPressed: () => Navigator.pop(context), child: new Text('no')),
            new FlatButton(onPressed: () => Navigator.pop(context), child: new Text('Ok'))
          ],
        )

    );
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Name here'),
        backgroundColor: Colors.red,
      ),
      //hit Ctrl+space in intellij to know what are the options you can use in flutter widgets
      body: new Container(
        padding: new EdgeInsets.all(32.0),
        child: new Center(
          child: new Column(
            children: <Widget>[
              new Text('Add widgets here'),
              new RaisedButton(onPressed: () => _showAlert(context, 'Do you like flutter, I do!'), child: new Text('Click me'),)
            ],
          ),
        ),
      ),
    );
  }
}

複製代碼

BottomSheet

簡介

BottomSheet 是一個從屏幕底部滑起的列表(以顯示更多的內容)。你能夠調用showBottomSheet() 或 showModalBottomSheet 彈出

經常使用屬性

屬性名 類型 說明
animationController AnimationController 控制底部工做表位置的動畫
builder WidgetBuilder 工做表內容的構建器。
elevation double 將此材質相對於其父級放置的z座標。
onClosing VoidCallback 當底部紙張開始關閉時調用
enableDrag bool 若是爲 true,則能夠經過向下滑動來向上和向下拖動底部紙張

簡單示例

import 'package:flutter/material.dart';

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

class BottomSheetPage extends StatefulWidget {
  @override
  _BottomSheetPageState createState() => _BottomSheetPageState();
}

class _BottomSheetPageState extends State<BottomSheetPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BottomSheet 示例'),
      ),
      body: Container(
        child: Center(
            child: FlatButton(
              color: Colors.red,
                onPressed: () => showBottom(context), child: Text('showBottomSheet'))),
      ),
    );
  }
}

Future<Widget> showBottom(BuildContext buildContext) async {
 return await showModalBottomSheet(
     context: buildContext, builder: (context){
   return ListView.builder(
       itemCount: 100,
       itemBuilder: (context,index){
     return ListTile(
       onTap: (){
         print("index:$index");
         Navigator.pop(context);
       },
       leading:Icon(Icons.ac_unit),title:Text('Dev_Yk:$index'),
     );
   });
 });

}

複製代碼

ExpansionPanel

簡介

擴展面板包含建立流程,容許輕量編輯元素。 ExpansionPanel 小部件實現此組件。

經常使用屬性

屬性名 類型 說明
body Widget 擴展面板的主體顯示在標題下方。
headerBuilder ExpansionPanelHeaderBuilder 構建擴展面板標題的小組件構建器。
isExpander bool 面板是否擴展。

簡單示例

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: ExpansionPanelListDemo(),
  ));
}

class ExpansionPanelListDemo extends StatefulWidget {
  @override
  _ExpansionPanelListDemoState createState() => _ExpansionPanelListDemoState();
}

class ExpandStateBean{
  var isOpen;
  var index;
  ExpandStateBean(this.index,this.isOpen);
}

class _ExpansionPanelListDemoState extends State<ExpansionPanelListDemo> {
  var currentPanelIndex = -1;
  List<int> mList;
  List<ExpandStateBean> expandStateList;
  _ExpansionPanelListDemoState() {
    mList = new List();
    expandStateList=new List();
    for (int i = 0; i < 10; i++) {
      mList.add(i);
      expandStateList.add(ExpandStateBean(i, false));
    }
  }


  _setCurrentIndex(int index,isExpand) {
    setState(() {
      expandStateList.forEach((item){
        if (item.index==index) {
          item.isOpen=!isExpand;
        }
      });

    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("ExpansionPanel 示例"),
        ),
        body: SingleChildScrollView(child: ExpansionPanelList(
          children: mList.map((index) {
            return new ExpansionPanel(
              headerBuilder: (context, isExpanded) {
                return new ListTile(
                  title: new Text('我是第$index個標題'),
                );
              },
              body: new Padding(
                padding: EdgeInsets.symmetric(horizontal: 5.0),
                child: Container(height: 100.0,
                  color: Colors.blue,
                  alignment: Alignment.center,
                  child:Icon(Icons.security,size: 35.0,),),
              ),
              isExpanded: expandStateList[index].isOpen,
            );
          }).toList(),

          expansionCallback: (index, bol) {
            _setCurrentIndex(index,bol);
          },

        ),));
  }
}
複製代碼

SnackBar

簡介

具備可選操做的輕量級消息提示,在屏幕的底部顯示。

經常使用屬性

屬性名 類型 說明
action SnackBarAction (可選)用戶能夠根據小吃店執行的操做。
animatiion Animation 入口和出口的動畫
backgroundColor Color Snackbar 的背景顏色。默認狀況下,顏色爲深灰色
content Widget 主要內容
duration Duration 應該顯示時間長度

簡單示例

import 'package:flutter/material.dart';

void main() => runApp(
      MaterialApp(
        home: SnackBarPage(),
      ),
    );

class SnackBarPage extends StatefulWidget {
  @override
  _SnackBarPageState createState() => _SnackBarPageState();
}

class _SnackBarPageState extends State<SnackBarPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SnackBar 示例'),
      ),
      body: Center(
        child: new ListView(
          children: <Widget>[
            new FlatButton(
              onPressed: null,
              child: new Text('我是按鈕'),
            ),
            new Builder(builder: (BuildContext context) {
              return new Center(
                child: new GestureDetector(
                  onTap: () {
                    final mySnackBar = SnackBar(
                      content: new Text('我是SnackBar'),
                      backgroundColor: Colors.red,
                      duration: Duration(seconds: 1),
                      action: new SnackBarAction(label: '我是scackbar按鈕', onPressed: () {
                        print('點擊了snackbar按鈕');
                      }),
                    );
                    Scaffold.of(context).showSnackBar(mySnackBar);
                  },
                  child: new Text('點我顯示SnackBar'),
                ),
              );
            }),
          ],
        ),
      ),
    );
  }
}
複製代碼

信息展現

Image

請參考目錄 基礎Widget/圖像 Image

Icon

請參考目錄 基礎Widget/圖標 Icon

Chip

簡介

標籤,一個 Material widget 。 它能夠將一個複雜內容實體展示在一個小塊中,如聯繫人。

經常使用屬性

屬性名 類型 說明
avatar Widget 在芯片標籤以前顯示的小部件。
backgroudColor Color 用於未選定的啓用芯片背景的顏色
clipBehavior Clip 根據此選項,內容將被剪裁(或不剪輯)
deleteButtonTooltipMessage String 用於芯片刪除按鈕工具提示的消息。
deleteIcon Widget 設置 onDeleted 時顯示的圖標。
deleteIconColor Color 刪除圖標的顏色。默認值基於環境 IconTheme.color
elevation double 相對於其父級在芯片上應用的高程。
label Widget 芯片的主要內容
labelStyle TextStyle 要應用於芯片標籤的樣式
materialTapTargetSize MaterialTapTargetSize 配置點擊目標的最小尺寸
onDeleted VoidCallback 當用戶點擊 deleteIcon 刪除芯片時調用
padding EdgeInsetsGeometry 芯片內容與外形之間的填充
shape ShapeBorder ShapeBorder 在芯片周圍繪製

簡單示例

import 'package:flutter/material.dart';

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

class ClipSample extends StatefulWidget {
  @override
  _ClipSampleState createState() => _ClipSampleState();
}

class _ClipSampleState extends State<ClipSample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Clip Sample"),
      ),
      body: Center(
        child: Chip(
          avatar: CircleAvatar(
            backgroundColor: Colors.grey.shade800,
            child: Text('Dev'),
          ),
          label: Text('YKun'),
        ),
      ),
    );
  }
}

複製代碼

Tooltip

簡介

一個文本提示工具,幫助解釋一個按鈕或其餘用戶界面,當widget長時間按下時(當用戶採起其餘適當操做時)顯示一個提示標籤。

經常使用屬性

屬性名 類型 說明
child widget 樹中此小部件下方的小部件
excludeFromSemantics bool 是否應從語義樹中排除工具提示的消息。
height double 工具提示應占用的垂直空間量(在其填充內)。
message String 要在工具提示中顯示的文本
padding EdgeInsetsGeometry 插入孩子的空間量
preferBelow bool 工具提示是否默認顯示在窗口小部件下方
verticalOffset double 窗口小部件與顯示的工具提示之間的垂直距離量

簡單示例

// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

void main()=>runApp(MaterialApp(home: TooltipDemo(),));
const String _introText =
    'Tooltips are short identifying messages that briefly appear in response to '
    'a long press. Tooltip messages are also used by services that make Flutter '
    'apps accessible, like screen readers.';

class TooltipDemo extends StatelessWidget {

  static const String routeName = '/material/tooltips';

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tooltips'),
      ),
      body: Builder(
          builder: (BuildContext context) {
            return SafeArea(
              top: false,
              bottom: false,
              child: ListView(
                children: <Widget>[
                  Text(_introText, style: theme.textTheme.subhead),
                  Row(
                    children: <Widget>[
                      Text('Long press the ', style: theme.textTheme.subhead),
                      Tooltip(
                        message: 'call icon',
                        child: Icon(
                          Icons.call,
                          size: 18.0,
                          color: theme.iconTheme.color,
                        ),
                      ),

                      Tooltip(
                        message: '長按我顯示了',
                        child: Text('測試點擊顯示', style: theme.textTheme.subhead),
                      ),
                      Text(' icon.', style: theme.textTheme.subhead),
                    ],
                  ),
         /* Center( child: IconButton( iconSize: 48.0, icon: const Icon(Icons.call), color: theme.iconTheme.color, tooltip: 'Place a phone call', onPressed: () { Scaffold.of(context).showSnackBar(const SnackBar( content: Text('That was an ordinary tap.'), )); }, ), ),*/
                ]
                    .map<Widget>((Widget widget) {
                  return Padding(
                    padding: const EdgeInsets.only(top: 16.0, left: 16.0, right: 16.0),
                    child: widget,
                  );
                })
                    .toList(),
              ),
            );
          }
      ),
    );
  }
}
複製代碼

DataTable

簡介

數據表顯示原始數據集。它們一般出如今桌面企業產品中。DataTable Widget 實現這個組件

經常使用屬性

屬性名 類型 說明
columns List 表中列的配置和標籤。
onSelectAll ValueSetter 當用戶使用標題行中的複選框選擇或取消選擇每一行時調用.
rows List 每行顯示的數據(不包括列標題的行)。必須爲非 null ,但能夠爲空.
sortAscending bool sortColumnIndex 中提到的列是否按升序排序。
sortColumnIndex int 當前主排序鍵的列。

簡單示例

// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

void main()=>runApp(MaterialApp(home: DataTableDemo(),));
class Dessert {
  Dessert(this.name, this.calories, this.fat, this.carbs, this.protein, this.sodium, this.calcium, this.iron);
  final String name;
  final int calories;
  final double fat;
  final int carbs;
  final double protein;
  final int sodium;
  final int calcium;
  final int iron;

  bool selected = false;
}

class DessertDataSource extends DataTableSource {
  final List<Dessert> _desserts = <Dessert>[
    Dessert('Frozen yogurt',                        159,  6.0,  24,  4.0,  87, 14,  1),
    Dessert('Ice cream sandwich',                   237,  9.0,  37,  4.3, 129,  8,  1),
    Dessert('Eclair',                               262, 16.0,  24,  6.0, 337,  6,  7),
    Dessert('Cupcake',                              305,  3.7,  67,  4.3, 413,  3,  8),
    Dessert('Gingerbread',                          356, 16.0,  49,  3.9, 327,  7, 16),
    Dessert('Jelly bean',                           375,  0.0,  94,  0.0,  50,  0,  0),
    Dessert('Lollipop',                             392,  0.2,  98,  0.0,  38,  0,  2),
    Dessert('Honeycomb',                            408,  3.2,  87,  6.5, 562,  0, 45),
    Dessert('Donut',                                452, 25.0,  51,  4.9, 326,  2, 22),
    Dessert('KitKat',                               518, 26.0,  65,  7.0,  54, 12,  6),

    Dessert('Frozen yogurt with sugar',             168,  6.0,  26,  4.0,  87, 14,  1),
    Dessert('Ice cream sandwich with sugar',        246,  9.0,  39,  4.3, 129,  8,  1),
    Dessert('Eclair with sugar',                    271, 16.0,  26,  6.0, 337,  6,  7),
    Dessert('Cupcake with sugar',                   314,  3.7,  69,  4.3, 413,  3,  8),
    Dessert('Gingerbread with sugar',               345, 16.0,  51,  3.9, 327,  7, 16),
    Dessert('Jelly bean with sugar',                364,  0.0,  96,  0.0,  50,  0,  0),
    Dessert('Lollipop with sugar',                  401,  0.2, 100,  0.0,  38,  0,  2),
    Dessert('Honeycomb with sugar',                 417,  3.2,  89,  6.5, 562,  0, 45),
    Dessert('Donut with sugar',                     461, 25.0,  53,  4.9, 326,  2, 22),
    Dessert('KitKat with sugar',                    527, 26.0,  67,  7.0,  54, 12,  6),

    Dessert('Frozen yogurt with honey',             223,  6.0,  36,  4.0,  87, 14,  1),
    Dessert('Ice cream sandwich with honey',        301,  9.0,  49,  4.3, 129,  8,  1),
    Dessert('Eclair with honey',                    326, 16.0,  36,  6.0, 337,  6,  7),
    Dessert('Cupcake with honey',                   369,  3.7,  79,  4.3, 413,  3,  8),
    Dessert('Gingerbread with honey',               420, 16.0,  61,  3.9, 327,  7, 16),
    Dessert('Jelly bean with honey',                439,  0.0, 106,  0.0,  50,  0,  0),
    Dessert('Lollipop with honey',                  456,  0.2, 110,  0.0,  38,  0,  2),
    Dessert('Honeycomb with honey',                 472,  3.2,  99,  6.5, 562,  0, 45),
    Dessert('Donut with honey',                     516, 25.0,  63,  4.9, 326,  2, 22),
    Dessert('KitKat with honey',                    582, 26.0,  77,  7.0,  54, 12,  6),

    Dessert('Frozen yogurt with milk',              262,  8.4,  36, 12.0, 194, 44,  1),
    Dessert('Ice cream sandwich with milk',         339, 11.4,  49, 12.3, 236, 38,  1),
    Dessert('Eclair with milk',                     365, 18.4,  36, 14.0, 444, 36,  7),
    Dessert('Cupcake with milk',                    408,  6.1,  79, 12.3, 520, 33,  8),
    Dessert('Gingerbread with milk',                459, 18.4,  61, 11.9, 434, 37, 16),
    Dessert('Jelly bean with milk',                 478,  2.4, 106,  8.0, 157, 30,  0),
    Dessert('Lollipop with milk',                   495,  2.6, 110,  8.0, 145, 30,  2),
    Dessert('Honeycomb with milk',                  511,  5.6,  99, 14.5, 669, 30, 45),
    Dessert('Donut with milk',                      555, 27.4,  63, 12.9, 433, 32, 22),
    Dessert('KitKat with milk',                     621, 28.4,  77, 15.0, 161, 42,  6),

    Dessert('Coconut slice and frozen yogurt',      318, 21.0,  31,  5.5,  96, 14,  7),
    Dessert('Coconut slice and ice cream sandwich', 396, 24.0,  44,  5.8, 138,  8,  7),
    Dessert('Coconut slice and eclair',             421, 31.0,  31,  7.5, 346,  6, 13),
    Dessert('Coconut slice and cupcake',            464, 18.7,  74,  5.8, 422,  3, 14),
    Dessert('Coconut slice and gingerbread',        515, 31.0,  56,  5.4, 316,  7, 22),
    Dessert('Coconut slice and jelly bean',         534, 15.0, 101,  1.5,  59,  0,  6),
    Dessert('Coconut slice and lollipop',           551, 15.2, 105,  1.5,  47,  0,  8),
    Dessert('Coconut slice and honeycomb',          567, 18.2,  94,  8.0, 571,  0, 51),
    Dessert('Coconut slice and donut',              611, 40.0,  58,  6.4, 335,  2, 28),
    Dessert('Coconut slice and KitKat',             677, 41.0,  72,  8.5,  63, 12, 12),
  ];

  void _sort<T>(Comparable<T> getField(Dessert d), bool ascending) {
    _desserts.sort((Dessert a, Dessert b) {
      if (!ascending) {
        final Dessert c = a;
        a = b;
        b = c;
      }
      final Comparable<T> aValue = getField(a);
      final Comparable<T> bValue = getField(b);
      return Comparable.compare(aValue, bValue);
    });
    notifyListeners();
  }

  int _selectedCount = 0;

  @override
  DataRow getRow(int index) {
    assert(index >= 0);
    if (index >= _desserts.length)
      return null;
    final Dessert dessert = _desserts[index];
    return DataRow.byIndex(
      index: index,
      selected: dessert.selected,
      onSelectChanged: (bool value) {
        if (dessert.selected != value) {
          _selectedCount += value ? 1 : -1;
          assert(_selectedCount >= 0);
          dessert.selected = value;
          notifyListeners();
        }
      },
      cells: <DataCell>[
        DataCell(Text('${dessert.name}')),
        DataCell(Text('${dessert.calories}')),
        DataCell(Text('${dessert.fat.toStringAsFixed(1)}')),
        DataCell(Text('${dessert.carbs}')),
        DataCell(Text('${dessert.protein.toStringAsFixed(1)}')),
        DataCell(Text('${dessert.sodium}')),
        DataCell(Text('${dessert.calcium}%')),
        DataCell(Text('${dessert.iron}%')),
      ],
    );
  }

  @override
  int get rowCount => _desserts.length;

  @override
  bool get isRowCountApproximate => false;

  @override
  int get selectedRowCount => _selectedCount;

  void _selectAll(bool checked) {
    for (Dessert dessert in _desserts)
      dessert.selected = checked;
    _selectedCount = checked ? _desserts.length : 0;
    notifyListeners();
  }
}

class DataTableDemo extends StatefulWidget {
  static const String routeName = '/material/data-table';

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

class _DataTableDemoState extends State<DataTableDemo> {
  int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;
  int _sortColumnIndex;
  bool _sortAscending = true;
  final DessertDataSource _dessertsDataSource = DessertDataSource();

  void _sort<T>(Comparable<T> getField(Dessert d), int columnIndex, bool ascending) {
    _dessertsDataSource._sort<T>(getField, ascending);
    setState(() {
      _sortColumnIndex = columnIndex;
      _sortAscending = ascending;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Data tables'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(20.0),
        children: <Widget>[
          PaginatedDataTable(
            header: const Text('Nutrition'),
            rowsPerPage: _rowsPerPage,
            onRowsPerPageChanged: (int value) { setState(() { _rowsPerPage = value; }); },
            sortColumnIndex: _sortColumnIndex,
            sortAscending: _sortAscending,
            onSelectAll: _dessertsDataSource._selectAll,
            columns: <DataColumn>[
              DataColumn(
                label: const Text('Dessert (100g serving)'),
                onSort: (int columnIndex, bool ascending) => _sort<String>((Dessert d) => d.name, columnIndex, ascending),
              ),
              DataColumn(
                label: const Text('Calories'),
                tooltip: 'The total amount of food energy in the given serving size.',
                numeric: true,
                onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.calories, columnIndex, ascending),
              ),
              DataColumn(
                label: const Text('Fat (g)'),
                numeric: true,
                onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.fat, columnIndex, ascending),
              ),
              DataColumn(
                label: const Text('Carbs (g)'),
                numeric: true,
                onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.carbs, columnIndex, ascending),
              ),
              DataColumn(
                label: const Text('Protein (g)'),
                numeric: true,
                onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.protein, columnIndex, ascending),
              ),
              DataColumn(
                label: const Text('Sodium (mg)'),
                numeric: true,
                onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.sodium, columnIndex, ascending),
              ),
              DataColumn(
                label: const Text('Calcium (%)'),
                tooltip: 'The amount of calcium as a percentage of the recommended daily amount.',
                numeric: true,
                onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.calcium, columnIndex, ascending),
              ),
              DataColumn(
                label: const Text('Iron (%)'),
                numeric: true,
                onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.iron, columnIndex, ascending),
              ),
            ],
            source: _dessertsDataSource,
          ),
        ],
      ),
    );
  }
}
複製代碼

Card

簡介

一個 Material Design 卡片。擁有一個圓角和陰影

經常使用屬性

屬性名 類型 說明
borderOnForeground bool 是否在孩子面前畫形狀邊框26
child Widget 樹中此小部件下方的小部件
clipBebavior Clip 根據此選項,內容將被剪裁(或不剪輯)
color double 放置此卡的z座標。這能夠控制卡下方陰影的大小。
margin DegeInsetsGeometry 卡片周圍的空白區域
semanticContainer bool 此窗口小部件是表示單個語義容器,仍是 false 表示單個語義節點的集合。
shape ShapeBorder 卡片材質的形狀。

簡單示例

// This sample shows creation of a [Card] widget that shows album information
// and two actions.

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: 'Flutter Code Sample for material.Card',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Card 示例'),
        ),
        body: MyStatelessWidget(),
      ),
    );
  }
}

class MyStatelessWidget extends StatelessWidget {
  MyStatelessWidget({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(itemBuilder: (context,index){
      return Card(
        margin: EdgeInsets.all(5.0),
        child: const ListTile(
          leading: Icon(Icons.album),
          title: Text('The Enchanted Nightingale'),
          subtitle: Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
        ),
      );
    });
  }
}
複製代碼

LinearProgressIndicator

簡介

一個線性進度條,另外還有一個圓形進度條 CircularProgressIndicator

經常使用屬性

屬性名 類型 說明
backgroudColor Color 進度指示器的背景顏色。默認狀況下,當前主題的ThemeData.backgroundColor。

簡單示例

import 'package:flutter/material.dart';

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

class LinearProgressIndicatorPage extends StatefulWidget {
  @override
  _LinearProgressIndicatorPageState createState() => _LinearProgressIndicatorPageState();
}

class _LinearProgressIndicatorPageState extends State<LinearProgressIndicatorPage> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('LinearProgressIndicator 示例'),
        ),
        body: LinearProgressIndicator(
          backgroundColor: Colors.red,
        ),
      ),
    );
  }
}


複製代碼

佈局

ListTile

簡介

一個固定高度的行,一般包含一些文本,以及一個行前或行尾圖標。

經常使用屬性

屬性名 類型 說明
contentPadding EdgeInsetsGeometry 內部填充
dense bool 此列表圖塊是不是垂直密集列表的一部分
enable bool 此列表圖塊是不是交互式的
isThreeLine bool 此列表圖塊是否旨在顯示三行文本
leading Widget 要在標題以前顯示的小部件
onLongPress GestureTapCallback 當用戶長按此列表磁貼時調用
onTap GestureTapCallback 當用戶點擊此列表磁貼時調用
selected bool 若是此圖塊也已啓用,則圖標和文本將以相同顏色呈現
title Widget 列表主要內容
trailing Widget 標題後顯示的小部件
subtitle Widget 標題下方顯示的其餘內容

簡單示例

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: ListTitlePage(),
    ));

class ListTitlePage extends StatefulWidget {
  @override
  _ListTitlePageState createState() => _ListTitlePageState();
}

class _ListTitlePageState extends State<ListTitlePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListTitle 示例'),
      ),
      body: ListView.builder(
          itemCount: 100,
          itemBuilder: (BuildContext context, int index) {
            return ListTile(
              leading: Icon(Icons.supervised_user_circle),
              title: Text('小明$index'),
              trailing: Icon(Icons.backup),
            );
          }),
    );
  }
}

複製代碼

Stepper

簡介

一個 Material Design 步驟指示器,顯示一系列步驟的過程

經常使用屬性

屬性名 類型 說明
controlsBuilder ControlsWidgetBuild 用於建立自定義控件的回調
currentStep int 顯示內容的當前步驟的索引的索引
onStepCancel VoidCallback 點擊「取消」按鈕時調用回調
onStepTapped ValueChanged 回調一個步驟時調用的回調,其索引做爲參數傳遞。
physics ScrollPhysics 步進器的滾動視圖應如何響應用戶輸入。
steps List 步進器的步驟,標題,副標題,圖標老是顯示。
type StepperType 肯定佈局的步進器類型。在StepperType.horizontal 的狀況下,當前步驟的內容顯示在下面,而不是StepperType.vertical 狀況,其中顯示在其間。

簡單示例

import 'package:flutter/material.dart';

void main() =>
    runApp(new MaterialApp(title: "Stepper 示例", home: new StepperPage()));

class StepperPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => StepperPageState();
}

class StepperPageState extends State<StepperPage> {
  int current_step = 0;
  List<Step> my_steps = [
    new Step(
        title: new Text("Step 1"), content: new Text("Hello"), isActive: true),
    new Step(
        title: new Text("Step 2"), content: new Text("World"), isActive: true),
    new Step(
        title: new Text("Step 3"),
        content: new Text("Hello World"),
        isActive: true)
  ];
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar:
      new AppBar(title: new Center(child: new Text("Stepper 示例"))),
      body: new Container(
        child: new Stepper(
          currentStep: this.current_step,
          steps: my_steps,
          type: StepperType.vertical,
          onStepTapped: (step) {
            setState(() {
              current_step = step;
            });
          },
          onStepCancel: () {
            setState(() {
              if (current_step > 0) {
                current_step = current_step - 1;
              } else {
                current_step = 0;
              }
            });
          },
          onStepContinue: () {
            setState(() {
              if (current_step < my_steps.length - 1) {
                current_step = current_step + 1;
              } else {
                current_step = 0;
              }
            });
          },
        ),
      ),
    );
  }
}

複製代碼

Divider

簡介

一個邏輯1像素厚的水平分割線,兩邊都有填充

經常使用屬性

屬性名 類型 說明
color Color 虛線的背景色
height double 虛線的高度
indent double 分隔左邊的空白空間量

簡單示例

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: ListTitlePage(),
    ));

class ListTitlePage extends StatefulWidget {
  @override
  _ListTitlePageState createState() => _ListTitlePageState();
}

class _ListTitlePageState extends State<ListTitlePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Divider 示例'),
      ),
      body: Column(
        children: <Widget>[
          ListTile(
            leading: Icon(Icons.supervised_user_circle),
            title: Text('小明'),
            trailing: Icon(Icons.backup),
          ),
          Divider(
            height: 10.0,
            color: Color(0xffff0000),
          ),
          ListTile(
            leading: Icon(Icons.supervised_user_circle),
            title: Text('小明'),
            trailing: Icon(Icons.backup),
          ),
          Divider(
            height: 10.0,
            color: Color(0xffff0000),
          )
        ],
      ),
    );
  }
}

複製代碼

感謝

  1. Flutter 中文網
  2. Flutter GitHub 託管地址
相關文章
相關標籤/搜索