Flutter (四) 基础 Widgets、Material Components Widget 全面介绍

基础 Widgets

重要概念

一切皆组件。Flutter 所有的元素都是由组件组成。比如一个布局元素、一个动画、一个装饰效果等。

容器 Container

容器组件 Container 包含一个子 widget ,自身具备 alignment 、padding 等属性 ,方便布局过程中摆放 child 。

属性

属性名类型说明
keyKey控制一个小部件如何替换树中的另一个小部件
alignmentAlignmentGeometry将孩子与容器内的对齐,如果 Container或者 Container 的父节点尺寸大于 child 的尺寸,该属性设置会起作用,有很多种对齐方式。
childWidget容器所包含的孩子
constraintsBoxConstraints添加到child上额外的约束条件
decorationDecoration绘制在child后面的修饰,设置了Decoration的话,就不能设置color属性,否则会报错,此时应该在Decoration中进行颜色的设置
foregroundDecorationDecoration绘制在child前面的装饰
marginEdgeInsetsGeometry围绕在 Decoration 和 child 之外的空白区域,不属于内容区域
paddingEdgeInsetsGeometryDecoration 内部的空白区,如果有 child ,child 位于 padding 内部。
transformMatrix4设置 Container 的变换矩阵,类型为Matrix4
  • padding 与 margin 的不同之处:padding 是包含在 Content 内,而 margin 是外部边界。设置点击事件的话,padding 区域会响应,而 margin 区域不会响应。

简单示例

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 的列表

属性类型说明
keyKey控制一个小部件如何替换树中的另一个小部件
childrenList树中此小部件下方的小部件
crossAxisAlignmentCrossAxisAlignment如何将孩子对齐
directionAxis用作主轴的方向

简单示例

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的列表

属性

属性类型说明
keyKey控制一个小部件如何替换树中的另一个小部件
childrenList树中此小部件下方的小部件
crossAxisAlignmentCrossAxisAlignment如何将孩子对齐
directionAxis用于方向
mainAxisAlignmentMainAxisAlignment主轴方向上的对齐方式,会对child的位置起作用,默认是start
mainAxisSizeMainAxisSize在主轴方向占有空间的值,默认是max
textDirectionTextDirection确定水平放置孩子的顺序以及如何解释水平方向的开始和结束
verticalDirectionVerticalDirection确定垂直放置孩子的顺序以及如何解释垂直方向的开始和结束

简单示例

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,加载一张网络图片

属性

属性类型说明
keyKey控制一个小部件如何替换树中的另一个小部件
alignmentAlignmentGeometry如何在图像范围内对齐图像
centerSliceRect当图片需要被拉伸显示的时候,centerSlice 定义的矩形区域会被拉伸,可以理解成我们在图片内部定义来一个点 9 文件用作拉伸
colorColor如果不为 null,则使用 colorBlendMode 将此 Color 与每个图像像素混合
colorBlendModeBlendMode用于将 Color 与此图像组合
excludeFromSemanticsbool是否从 Semantics 排除此图像
filterQualityFilterQuality用于设置图像的滤清器质量
fitBoxFit对图像显示的控制
gaplessPlaybackbool当图像提供者更改时,是继续显示旧图像(true)还是简单地显示任何内容(false)
heightdouble
imageImageProvider要显示的图像
matchTextDirectionbool是否在 TextDirection 的方向上绘制图像
repeatImageRepeat如何绘制图像未覆盖的布局边界的任何部分
semanticLableString
widthdouble

简单示例

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

单一格式演示的文本

属性

属性类型说明
keyKey控制一个小部件如何替换树中的另一个小部件
dataString要显示的文字
localeLocale用于在可以以不同方式呈现相同Unicode字符时选择字体,具体取决于区域设置
maxLinesint文本要跨越的可选最大行数,必要时包装。如果文本超过给定的行数,则会根据溢出将其截断
overFlowTextoverFlow如何处理视觉溢出
semanticsLableString此文本的替代语义标签
softWrapbool文本是否应该在软换行符处中断
strutStyleStrutStyle要使用的支柱风格。 Strut样式定义了strut,它设置了最小垂直布局度量
styleTextStyle如果为非null,则为此文本使用的样式
textAlignTextAlign文本应如何水平对齐
textScaleFactordouble每个逻辑像素的字体像素数。
textSpanTextSpan要显示为TextSpan的文本
textDirectionTextDirection文本的方向性

简单示例

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)中的字形绘制

属性

属性类型说明
colorColor绘制图标使用的 Color
iconIconData要显示的图标。图标库 Icons 中有可用的图标
semanticLableString标志位
sizedouble大小
textDirectionTextDirection绘制方向,一般使用不到

图标库

凸起来的按钮 RaisedButton

Material Design 中的 button, 一个凸起的材质矩形按钮 ,它可以响应按下事件,并且按下时会带一个触摸效果。

属性

属性名类型默认值说明
colorColornull组件的 Color
disabledColorColorThemeData.disabledColor组件禁用状态的 Color ,默认为主题里的禁用 Color ,也可以设置为其他 Color
onPressedVoidCallbacknull当按钮按下时会触发此回调事件
childWidget-按钮的child通常为一个Text文本组件,用来显示按钮的文本
enablebooltrue按钮是否为禁用状态
RaisedButton(
              onPressed: null,
    		//  onPressed: (){},
              child: const Text('Disabled      Button'),
            ),
复制代码

脚手架 Scaffold

Material Design 布局结构的基本实现。此类提供了用于显示 drawer、snackbar 和底部 sheet 的API

属性

属性类型说明
appBarPreferredSizeWidget一个应用栏,显示在脚手架的顶部
backgroundColorColor作为整个脚手架基础的材质小部件的 Color
bodyWidget支架的主要内容
bottomNavigationBarWidget底部导航栏显示在脚手架的底部
bottomSheetwidget要显示的持久性底部工作表
drawerwidget显示在身体侧面的面板,通常隐藏在移动设备上。从左到右( TextDirection.ltr )或从右到左( TextDirection.rtl )滑入
drawerDragStartBebaviorDragStartBehavior确定处理拖动开始行为的方式
endDrawerWidget显示在身体侧面的面板,通常隐藏在移动设备上。从右到左( TextDirection.ltr )或从左到右( TextDirection.rtl )滑动
floatingActionButtonWidget显示在身体上方的按钮,位于右下角
floatingActionButtonAnimatorFloatingActionButtonAnimatorAnimator 将 floatingActionButton 移动到新的floatingActionButtonLocation。
floatingActionButtonLocationFloatingActionButtonLocation负责确定 floatingActionButton 的去向
persistentFooterButtonsList一组显示在脚手架底部的按钮
primarybool此脚手架是否显示在屏幕顶部
resizeToAvoidBottomInsetbool如果为 true ,则 body 和 scaffold 的浮动小部件应自行调整大小,以避免屏幕键盘的高度由环境MediaQuery 的 MediaQueryData.viewInsets 底部属性定义
resizeToAvoidBottomPaddingbool不推荐使用此标志,请改用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 是可以跟随内容滚动的。

常用属性

属性名类型默认值说明
actionsListnull要在标题 widget 后显示的widget
automaticallyImplyLeadingboolfalse控制是否应该尝试暗示前导widget 为null
backgroundColorColorThemeData.primaryColor用于应用栏材质的 Color 。通常这应该与亮度,iconTheme ,textTheme 一起设置
bottomPreferredSizeWidgetnull此小部件显示在应用栏的底部
bottomOpacitydouble应用栏底部的不透明程度
brightnessBrightnessThemeData.primaryColorBrightness应用栏材质的亮度。通常,这与backgroundColor,iconTheme,textTheme一起设置。
centerTitleboolfalse标题是否应该居中
elevationdouble4将此应用栏相对于其父级放置的 z 坐标
flexibleSpaceWidgetnull此小组件堆叠在工具栏和标签栏后面。它的高度与应用栏的整体高度相同
iconThemeIcomThemDataThemeData.primaryIconTheme用于应用栏图标的 Color ,不透明度和大小。通常,这与backgroundColor,brightness,textTheme一起设置
leadingWidgetnull要在标题之前显示的小部件
preferredSizeSize高度为kToolbarHeight和底部窗口小部件首选高度之和的大小
primarybool此应用栏是否显示在屏幕顶部
textThemeTextThemeThemeData.primaryTextTheme应用栏中用于文本的排版样式。通常,这与亮度backgroundColor,iconTheme一起设置
titleWidgetnullappbar中显示的主要小部件
titleSpacingdouble横轴上标题内容周围的间距。即使没有前导内容或操作,也会应用此间距。如果希望title占用所有可用空间,请将此值设置为 0.0
toolbarOpacitydouble应用栏的工具栏部分是多么不透明

简单示例

 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之间切换和浏览顶级视图

常用属性

属性名类型说明
currentIndexint当前索引
fixedColorColor选中按钮的 Color 。不指定则使用系统主题 Color
iconSizedouble按钮图形大小
itemsList<BottomNavigatorBarItem>底部导航栏按钮集。每一项是一个BottomNavigatorBarItem,包含icon图标和title文本
onTapValueChanged<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 页面视图组件一起使用。

常用属性

属性名类型说明
controllerTabController这个 widget 的选择和动画状态
dragStartBehaviorDragStartBehavior确定处理拖动开始行为的方式
indicatorPaddingEdgeInsetsGeometry显示在所选选项卡下方的线条的水平填充。对于 isScrollable 标签栏,指定kTabLabelPadding 会将指示符与 Tab小部件的选项卡文本以及除最短Tab.text 值之外的所有文本对齐
indicatorDecoration定义所选选项卡指示器的外观
indicatorColorColor显示在所选选项卡下方的线条 Color 。如果此参数为 null ,则使用 Theme 的indicatorColor 属性的值
indicatorSizeTabBarIndicatorSize定义如何计算选定选项卡指示符的大小
indicatorWeightdouble显示在所选选项卡下方的线条粗细。此参数的值必须大于零
isScrollablebool此选项卡栏是否可以水平滚动
labelColorColor选中 Tab 的 Color
labelPaddingTextStyle填充添加到每个选项卡标签
onTapValueChanged点击 TabBar 时调用的可选回调
preferredSizeSize高度取决于标签是否同时包含图标和文本的大小
tabsList通常是两个或多个 Tab 小部件的列表
unselectedLabelColorColor未选定标签标签的 Color
unselectedLableStyleTextStyle未选定标签标签的文本样式

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一起使用

常用属性

属性名类型说明
childrenList每个标签的小部件
controllerTabController此小部件的选择和动画状态
dragStartBebaviorDragStartBehavior确定处理拖动开始行为的方式
physicsScroolPhysics页面视图应如何响应用户输入

简单使用

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 这个主组件开始的。

常用属性

属性名类型说明
titleString应用程序的标题。该标题出现在以下位置:Android:任务管理器的程序快照上; IOS:程序切换管理器中
themeThemeData定义应用所使用的主题 Color ,可以指定主题中每个控件的 Color
colorColor应用的主要 Color 值,即 primary color
homeWidget用来定义当前应用打开时所显示的界面
routesMap<String, WidgetBuilder>定义应用中页面跳转规则
initialRouteString初始化路由
onGenerateRouteRouteFactory路由回调函数。当通过Navigator.of(context).pushNamed跳转路由的时候,在routes查找不到时,会调用该方法
onLocaleChanged-当系统修改语言的时候,会触发这个回调
navigatorObserversList<NavigatorObserver>导航观察器
debugShowMaterialGridbool是否显示布局网格,用来调试UI的工具
showPerformanceOverlaybool显示性能标签

设置主页

使用 home 属性设置应用的主页,及整个应用的主组件。

路由处理

routes 对象是一个 Map<String, WidgetBuilder> 。当使用 Navigator.pushNamed 来跳转路由的时候,通过 routes 查找路由名字,然后使用对应的 WidgetBuilder 来构造一个带有页面切换动画的 MaterialPageRoute 。如果应用只有一个界面,则不用设置整个属性,使用 home 即可。

自定义主题

应用程序的主题,各种定制的 Color 都可以设置,用于程序主题切换

WidgetsApp

一个方便的类,它封装了应用程序通常需要的一些widget

抽屉组件 Drawe

Drawer可以实现类似抽屉拉入推出的效果,通常与ListView组合使用。

常用属性

属性名类型默认值说明
childWidget-Drawer 的 child 可以放置任意可显示的组件
elevationdouble16阴影尺寸

Drawer可以添加头部效果:

  • DrawerHeader:展示基本信息
  • UserAccountsDrawerHeader:展示用户头像、用户名、Email等信息

DrawerHeader常用属性

属性名类型说明
decorationDecorationheader区域的decoration,通常用来设置背景 Color 或背景图片
curveCurve如果decoration发生了变化,则会使用curve设置的变化曲线和duration设置的动画时间来做一个动画效果
childWidgetHeader里面所显示的内容控件
paddingEdgeInsetsGeometryHeader里面内容控件的padding值,如果child为null,该值无效
marginEdgeInsetsGeometryHeader四周的间隙

UserAccountsDrawerHeader常用属性

属性名类型说明
marginEdgeInsetsGeometryHeader四周的间隙
decorationDecorationheader区域的decoration,通常用来设置背景 Color 或背景图片
currentAccountPictureWidget用来设置当前用户的头像
otherAccountsPictureWidget用来设置当前用户其他账号的头像
accountNameWidget当前用户的名字
accountEmailWidget当前用户的Email
onDetailsPressedVoidCallback当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 , 一个凸起的材质矩形按钮。

常用属性

属性名类型说明
animationDurationDuration定义形状和高程的动画更改的持续时间
childWidget按钮的标签
clipBehaviorClip根据此选项,内容将被剪裁(或不剪辑)
colorColor按钮的填充 Color ,由其材料显示,同时处于默认(未按下,已启用)状态
colorBrightnessBrightness用于此按钮的主题亮度
disabledColorColor禁用按钮时按钮的填充 Color
disabledTextColorColor禁用按钮时用于此按钮文本的 Color
elevationdouble将此按钮相对于其父级放置的z坐标
enabledbool是启用还是禁用按钮
heightdouble按钮的垂直范围
highightColorColor按钮的InkWell的高亮 Color
highlightElevationdouble启用并按下按钮时按钮的材质相对于其父级的高程
materialTapTargetSizeMaterialTapTargetSize配置点击目标的最小尺寸
minWidthdouble按钮占据的最小水平范围
onHighlightChangedValueChanged由底层 InkWell 小部件的InkWell.onHighlightChanged 回调调用。
onPressedVoidCallback点击或以其他方式激活按钮时调用的回调
paddingEdgeInsetsGeometry按钮的孩子的内部填充
shapeShapeBorder按钮材质的形状
splashColorClor按钮 InkWell 的闪烁 Color
textColorColor用于此按钮文本的 Color 。
textThemeButtonTextTheme定义按钮的 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 字段。

常用属性

属性名类型说明
backgroudColorColor填充按钮时使用的 Color
childWidget树中此小部件下方的小部件
clipBehaviorClip根据此选项,内容将被剪裁(或不剪辑)。
disableElevationdouble禁用按钮时放置此按钮的 z 坐标( onPressed 为 null)
elevationdouble用于将此按钮与其父按钮相关联的z坐标
foregroudColorColor默认图标和文本 Color 。
heroTagObject要应用于按钮的Hero小部件的标记
highlightElevationdouble当用户触摸按钮时,将此按钮相对于其父按钮放置的z坐标
isExtendedbool如果这是一个“扩展”浮动操作按钮,则为 True
materialTapTargetSizeMaterialTapTargetSize配置点击目标的最小尺寸
minibool控制此按钮的大小
onPressedVoidCallback点击或以其他方式激活按钮时调用的回调
shapeShapeBorder按钮材质的形状
tooltipString描述按下按钮时将发生的操作的文本

简单示例

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

FlatButton

简介

一个扁平的 Material 按钮

常用属性

属性名类型说明
animationDurationDuration定义形状和高程的动画更改的持续时间
childWidget按钮的标签
chlipBebaviorClip根据此选项,内容将被剪裁(或不剪辑)
colorColor按钮的填充 Color ,由其材料显示,同时处于默认(未按下,已启用)状态
colorBrightnessBrightness用于此按钮的主题亮度
disabledColorColor禁用按钮时按钮的填充 Color
disableElevationdouble未启用按钮时按钮的材质相对于其父级的高程
disableTextColorColor禁用按钮时用于此按钮文本的 Color Color
elevationdouble将此按钮相对于其父级放置的z坐标。
enablebool是启用还是禁用按钮
heightdouble按钮的垂直范围
highlightColorColor按钮的 InkWell 的高亮 Color
highlightElevationdouble启用并按下按钮时按钮的材质相对于其父级的高程。
materialTapTargetSizeMaterialTapTargetSize配置点击目标的最小尺寸
minWidthdouble按钮占据的最小水平范围。
onHighlightChangedValueChanged由底层 InkWell 小部件的InkWell.onHighlightChanged 回调调用
onPressedVoidCallback点击或以其他方式激活按钮时调用的回调
paddingEdgeInsetsGeometry点击或以其他方式激活按钮时调用的回调。
shapeShapeBorder按钮材质的形状。
splashColorColor按钮 InkWell 的闪烁 Color
textColorColor用于此按钮文本的 Color 。
textThemeButtonTextTheme定义按钮的 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 图标按钮,点击时会有水波动画。

属性介绍

属性名类型说明
alignmentAlignmentGeometry定义图标在 IconButton 中的定位方式
colorColor如果启用了图标,则用于按钮内图标的 Color 。默认情况下将其留给图标小部件
disableColorColor如果图标被禁用,则用于按钮内图标的 Color 。默认为当前主题的 ThemeData.disabledColor 。
highlightColorColor按钮处于向下(按下)状态时按钮的辅助 Color 。 高亮 Color 表示为覆盖在按钮 Color (如果有)上的纯色。 如果突出显示 Color 具有透明度,则将显示按钮 Color 。 按住按钮时,突出显示会快速消失。
iconWidget要在按钮内显示的图标
iconSizedouble按钮内图标的大小。
onPressedVoidCallback按钮的回调
paddingEdgeInsetsGeometry按钮图标周围的填充。整个填充图标将对输入手势做出反应
splashColorColor按钮处于向下(按下)状态时按钮的主要 Color 。 飞溅表示为突出显示在 highlightColor 叠加层上方的圆形叠加层。 初始叠加层的中心点与用户触摸事件的生命点相匹配。 如果触摸持续足够长的时间,飞溅叠加将扩展以填充按钮区域。 如果初始 Color 具有透明度,则突出显示和按钮 Color 将显示
tooltipString描述按下按钮时将发生的操作的文本

简单示例

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 时显示一个弹出式菜单列表

常用属性

属性名类型说明
childWidget如果提供,则用于此按钮的小部件。
elevationdouble打开时放置菜单的z坐标。这可以控制菜单下方阴影的大小
iconIcon如果提供,则用于此按钮的图标
initialValueT菜单项的值(如果有),在菜单打开时应突出显示。
offsetOffset应用于弹出菜单按钮的偏移量
onCanceledPopupMenuCanceled当用户在不选择项目的情况下关闭弹出菜单时调用
onSelectedPopupMenuItemSelected当用户从此按钮创建的弹出菜单中选择一个值时调用
paddingEdgeInsetsGeometry默认情况下,匹配 IconButton 的 8 dps填充。在某些情况下,特别是在此按钮作为列表项的尾随元素出现的情况下,能够将填充设置为零是有用的。
tooltipString描述按下按钮时将发生的操作的文本
itemBuilderPopupMenuItemBuilder按下按钮时调用以创建要在菜单中显示的项目。

简单示例

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

简介

水平排列的按钮组

常用属性

属性名类型说明
alignmentMainAxisAlignment如何将孩子放在水平轴上
childrenList按钮水平排列
mainAxisSizeMainAxisSize有多少水平空间可供选择。请参见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

简介

一个文本输入框

常用属性

属性名类型说明
aotocorrectbool是否启用自动更正
autofocusbool如果没有其他内容已经集中,这个文本字段是否应该集中注意力
buildCounterInputCounterWidgetBuilder生成自定义InputDecorator.counter 小部件的回调
controllerTextEditingController绘制光标时使用的 Color 。
cursorColorColor绘制光标时使用的 Color
cursorRadiusRadius光标的角应该是多圆的
cursorWidthdouble光标的厚度。
decorationInputDecoration在文本字段周围显示的装饰。
dragStartBehaviorDragStartBehavior确定处理拖动开始行为的方式。
enablebool如果为 false,则文本字段为“禁用”:它忽略点击并且其装饰以灰 Color 呈现。
enableInteractiveSelectionbool如果为 true,则长按此TextField 将选择文本并显示剪切/复制/粘贴菜单,并且点击将移动文本插入符号。
focusNodeFocusNode定义此窗口小部件的键盘焦点
inputFormattersList可选的输入验证和格式覆盖。
keyboardAppearanceBrightness键盘的外观
keyboardTypeTextInputType用于编辑文本的键盘类型
maxLengthint如果为 true,则阻止该字段允许超过 maxLength 个字符
maxLinesint文本要跨越的最大行数,必要时包装
obsureTextbool是否隐藏正在编辑的文本(例如,用于密码)。
onCangedValueChanged当用户启动对 TextField 值的更改时调用:当他们插入或删除文本时。
onEditingCompleteVoidCallback当用户提交可编辑内容时调用(例如,用户按下键盘上的“完成”按钮)。
onSubmittedValueChanged当用户指示他们已完成编辑字段中的文本时调用
onTapGestureTapCallback当用户点击此文本字段时调用
scrollPaddingEdgeInsets当 Textfield 滚动到视图中时,将填充配置到Scrollable 周围的边缘。
selectionEnabledbool如果基于enableInteractiveSelection和obscureText 的值启用了交互式选择,则为 True。
styleTextStyle用于正在编辑的文本的样式。
textAlignTextAlign文本应如何水平对齐
textCapitalizationTextCapitalization配置平台键盘如何选择大写或小写键盘。
textDirectionTextDirection文本的方向性
textInputActionTextInputAction用于键盘的操作按钮类型

简单示例

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

简介

复选框,允许用户从一组中选择多个选项。

常用属性

属性名类型说明
activeColorColor选中此复选框时要使用的 Color
checkColorColor选中此复选框时用于检查图标的 Color
tristatebool如果为true,则复选框的值可以为true,false或null。
materialTapTargetSizeMaterialTapTargetSize配置点击目标的最小尺寸
onChangedValueChanged当复选框的值应该更改时调用
valuesbool是否选中此复选框

简单示例

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

简介

单选框,允许用户从一组中选择一个选项。

常用属性

属性名类型说明
activeColorColor选中的背景色
groupValueT此组单选按钮的当前选定值
materialTapTargetSizeMaterialTapTargetSize配置点击目标的最小尺寸。
onCangedValueChanged当用户选择此单选按钮时调用
valueT此单选按钮表示的值

简单示例

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 用于切换一个单一状态

常用属性

属性名类型说明
activeColorColor这个颜色代表选择时的背景色
groupValueT此组单选按钮的当前选定值
materialTapTargetSizeMaterialTapTargetSize配置点击目标的最小尺寸
onChangedValueChanged当用户选择此单选按钮时调用
valueT此单选按钮表示的值

简单示例

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

简介

滑块,允许用户通过滑动滑块来从一系列值中选择。

常用属性

属性名类型说明
activeColorColor用于滑块轨道中活动部分的颜色
divisionsint离散分数的数量
inactiveColorColor滑动轨道未滑动的颜色值
labelString滑块处于活动状态时显示在滑块上方的标签
maxdouble用户可以选择的最大值
mindouble用于可以选择的最小值
onChangedValueChanged滑动监听的值
onChangeEndValueChanged滑动结束
onChangeStartValueChanged滑动开始
semanticFormatterCallbackSemanticFormatterCallback回调用于从滑块值创建语义值
valuedouble此滑块的当前选定值

简单示例

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

简介

简单对话框可以显示附加的提示或操作

常用属性

属性名类型说明
backgroundColorColor此对话框表面的背景颜色
childrenList对话框的(可选)内容显示在标题下方的SingleChildScrollView 中
contentPaddingEdgeInsetsGeometry填充内容。
elevationdouble对话框的坐标
semanticLableString可访问性框架用于在打开和关闭对话框时通知屏幕转换的对话框的语义标签
shapeShapeBorder此对话框边框的形状
titleWidget对话框的(可选)标题在对话框顶部以大字体显示
titlePaddingEdgeInsetsGeometry在标题周围填充。

简单示例

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

简介

一个会中断用户操作的对话款,需要用户确认

常用属性

属性名类型说明
actionsList显示在对话框底部的(可选)操作集
backgroundColorColor此对话框表面的背景颜色
contentWidget对话框的(可选)内容以较浅的字体显示在对话框的中央
contentPaddingEdgeInsetsGeometry填充内容
contentTextStyleTextStyle此 AlertDialog 内容中文本的样式
elevationdouble此对话框的z坐标
semanticLableString可访问性框架用于在打开和关闭对话框时通知屏幕转换的对话框的语义标签。
titleWidget对话框的(可选)标题在对话框顶部以大字体显示。
titlePaddingEdgeInsetsGeometry在标题周围填充
titleTextStyleTextStyle此 AlertDialog 标题中文本的样式
shapeShapeBorder此对话框边框的形状。

简单示例

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 弹出

常用属性

属性名类型说明
animationControllerAnimationController控制底部工作表位置的动画
builderWidgetBuilder工作表内容的构建器。
elevationdouble将此材质相对于其父级放置的z坐标。
onClosingVoidCallback当底部纸张开始关闭时调用
enableDragbool如果为 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 小部件实现此组件。

常用属性

属性名类型说明
bodyWidget扩展面板的主体显示在标题下方。
headerBuilderExpansionPanelHeaderBuilder构建扩展面板标题的小组件构建器。
isExpanderbool面板是否扩展。

简单示例

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

简介

具有可选操作的轻量级消息提示,在屏幕的底部显示。

常用属性

属性名类型说明
actionSnackBarAction(可选)用户可以根据小吃店执行的操作。
animatiionAnimation入口和出口的动画
backgroundColorColorSnackbar 的背景颜色。默认情况下,颜色为深灰色
contentWidget主要内容
durationDuration应该显示时间长度

简单示例

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 。 它可以将一个复杂内容实体展现在一个小块中,如联系人。

常用属性

属性名类型说明
avatarWidget在芯片标签之前显示的小部件。
backgroudColorColor用于未选定的启用芯片背景的颜色
clipBehaviorClip根据此选项,内容将被剪裁(或不剪辑)
deleteButtonTooltipMessageString用于芯片删除按钮工具提示的消息。
deleteIconWidget设置 onDeleted 时显示的图标。
deleteIconColorColor删除图标的颜色。默认值基于环境 IconTheme.color
elevationdouble相对于其父级在芯片上应用的高程。
labelWidget芯片的主要内容
labelStyleTextStyle要应用于芯片标签的样式
materialTapTargetSizeMaterialTapTargetSize配置点击目标的最小尺寸
onDeletedVoidCallback当用户点击 deleteIcon 删除芯片时调用
paddingEdgeInsetsGeometry芯片内容与外形之间的填充
shapeShapeBorderShapeBorder 在芯片周围绘制

简单示例

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长时间按下时(当用户采取其他适当操作时)显示一个提示标签。

常用属性

属性名类型说明
childwidget树中此小部件下方的小部件
excludeFromSemanticsbool是否应从语义树中排除工具提示的消息。
heightdouble工具提示应占用的垂直空间量(在其填充内)。
messageString要在工具提示中显示的文本
paddingEdgeInsetsGeometry插入孩子的空间量
preferBelowbool工具提示是否默认显示在窗口小部件下方
verticalOffsetdouble窗口小部件与显示的工具提示之间的垂直距离量

简单示例

// 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 实现这个组件

常用属性

属性名类型说明
columnsList表中列的配置和标签。
onSelectAllValueSetter当用户使用标题行中的复选框选择或取消选择每一行时调用.
rowsList每行显示的数据(不包括列标题的行)。必须为非 null ,但可以为空.
sortAscendingboolsortColumnIndex 中提到的列是否按升序排序。
sortColumnIndexint当前主排序键的列。

简单示例

// 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 卡片。拥有一个圆角和阴影

常用属性

属性名类型说明
borderOnForegroundbool是否在孩子面前画形状边框26
childWidget树中此小部件下方的小部件
clipBebaviorClip根据此选项,内容将被剪裁(或不剪辑)
colordouble放置此卡的z坐标。这可以控制卡下方阴影的大小。
marginDegeInsetsGeometry卡片周围的空白区域
semanticContainerbool此窗口小部件是表示单个语义容器,还是 false 表示单个语义节点的集合。
shapeShapeBorder卡片材质的形状。

简单示例

// 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

常用属性

属性名类型说明
backgroudColorColor进度指示器的背景颜色。默认情况下,当前主题的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

简介

一个固定高度的行,通常包含一些文本,以及一个行前或行尾图标。

常用属性

属性名类型说明
contentPaddingEdgeInsetsGeometry内部填充
densebool此列表图块是否是垂直密集列表的一部分
enablebool此列表图块是否是交互式的
isThreeLinebool此列表图块是否旨在显示三行文本
leadingWidget要在标题之前显示的小部件
onLongPressGestureTapCallback当用户长按此列表磁贴时调用
onTapGestureTapCallback当用户点击此列表磁贴时调用
selectedbool如果此图块也已启用,则图标和文本将以相同颜色呈现
titleWidget列表主要内容
trailingWidget标题后显示的小部件
subtitleWidget标题下方显示的其他内容

简单示例

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 步骤指示器,显示一系列步骤的过程

常用属性

属性名类型说明
controlsBuilderControlsWidgetBuild用于创建自定义控件的回调
currentStepint显示内容的当前步骤的索引的索引
onStepCancelVoidCallback点击“取消”按钮时调用回调
onStepTappedValueChanged回调一个步骤时调用的回调,其索引作为参数传递。
physicsScrollPhysics步进器的滚动视图应如何响应用户输入。
stepsList步进器的步骤,标题,副标题,图标总是显示。
typeStepperType确定布局的步进器类型。在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像素厚的水平分割线,两边都有填充

常用属性

属性名类型说明
colorColor虚线的背景色
heightdouble虚线的高度
indentdouble分隔左边的空白空间量

简单示例

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 托管地址

转载于:https://juejin.im/post/5cbedc816fb9a03202221a37

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值