阅读 747

Material是什么?Scaffold脚手架如何使用?Material风格常用组件教程

Material

Flutter集成了material的组件。

Materia(官网需要科学上网)是谷歌的一套设计风格的组件,它为设计师提供了纸墨风格的整体的设计思路。原生安卓应用也遵循这套设计风格。

以下图片是官网的几个示例。

我们可以通过material组件快速生成一个好看的App。

比如我们可以通过materiApp快速生成一个导航栏,而不用考虑导航栏某个图标的具体位置、某个字的大小。

一个简单基本的结构

废话不多说。先走一个基本的程序。

使用MaterialApp组件,创建一个导航栏和一个hello word的文本。之后详解各个部件使用。

import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(      //  home 属性为App的入口
        appBar: AppBar(
          title: Text("这是第一个程序"),   
        ),
        body: Center(
          child: Text("Hello world"),
        ),
      ),
    );
  }
}

复制代码

如果我们不使用这种骨架,仍然使用material风格的背景颜色和字体样式。尝试手动写一个MyScaffold的骨架。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyScaffold(),
    );
  }
}

class MyScaffold extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Material(
      child: Column(
        children: <Widget>[
          MyAppBar(),
          Expanded(
            child: Center(child: Text("Hello world")),
          )
        ],
      ),
    );
  }
}

class MyAppBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 80, 
      padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
      decoration: BoxDecoration(color: Colors.blue[500]),
      child: Column(
        children: <Widget>[
          Spacer(),
          Expanded(
            flex: 2,
            child: Row(
              children: <Widget>[
                Expanded(
                  child: Text(
                    "这是第一个程序",
                    style: Theme.of(context).primaryTextTheme.title,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

void main() => runApp(MyApp());
复制代码

于是代码量变得很大。试想一下。如果从头手写整个骨架。代码量将会更大。

Scaffold脚手架

Scaffold脚手架是整个应用的骨架。我们可以将其抽象成还未被填词的旋律。我们拿到它只需要构建内容就完全可以了。当然,发现提供的旋律不是我们想要的也可以将某一部分替换成其他的,甚至整套样式都不喜欢我们也可将默认的样式都替换。

首先我们看一下scaffold的构造函数的参数。

Scaffold({Key key, PreferredSizeWidget appBar, Widget body, Widget floatingActionButton, FloatingActionButtonLocation floatingActionButtonLocation, FloatingActionButtonAnimator floatingActionButtonAnimator, List<Widget> persistentFooterButtons, Widget drawer, Widget endDrawer, Widget bottomNavigationBar, Widget bottomSheet, Color backgroundColor, bool resizeToAvoidBottomPadding, bool resizeToAvoidBottomInset, bool primary = true, DragStartBehavior drawerDragStartBehavior = DragStartBehavior.start, bool extendBody = false, Color drawerScrimColor, double drawerEdgeDragWidth})
复制代码
属性 构造函数或者类型
body Widget
appbar(导航栏) Widget
bottomNavigationBar(底部状态栏) BottomAppBar
floatingActionButton(悬浮按钮) FloatingActionButton
floatingActionButtonLocation(悬浮按钮位置) FloatingActionButtonLocation
drawer(侧边栏) Widget

我们再MaterialApp的home属性中添加构造函数Scaffold

创建一个简单的脚手架应用:

import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(   //导航栏
          title: Text("脚手架组件的示例"),
        ),
        body: Center(child:Text("Scaffold")),   // 身体部分
        bottomNavigationBar: BottomAppBar(   //  底部导航栏
          child: Container(
            height: 70.0,//高度
          ),
        ),
        floatingActionButton: FloatingActionButton(    //  悬浮按钮
          onPressed: (){},  //  点击事件(一般是一个函数)
          child: Icon(Icons.add),  //  图标样式
          tooltip: "增加",     // 提示信息
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,// 悬浮按钮的位置
        drawer: Icon(    //侧边栏
          Icons.menu    //图标样式
        ),
      ),
    );
  }
}
复制代码

AppBar导航栏

首先介绍Scaffold的参数appBar。

appBar属性的参数类型为PreferredSizeWidget。构造函数是AppBar

AppBar({Key key, Widget leading, bool automaticallyImplyLeading = true, Widget title, List<Widget> actions, Widget flexibleSpace, PreferredSizeWidget bottom, double elevation, ShapeBorder shape, Color backgroundColor, Brightness brightness, IconThemeData iconTheme, IconThemeData actionsIconTheme, TextTheme textTheme, bool primary = true, bool centerTitle, double titleSpacing = NavigationToolbar.kMiddleSpacing, double toolbarOpacity = 1.0, double bottomOpacity = 1.0})
复制代码

在material官网上我们可以看到这样的样式。只要在AppBar的属性写就可以在相应的位置补充内容。

import 'package:flutter/material.dart';

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

class Layout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: Icon(Icons.menu),
      
        title: Text("AppBar"),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.search),
            tooltip: '搜索',
            onPressed: () {},
          ),
          IconButton(
            icon: Icon(Icons.add),
            tooltip: '添加',
            onPressed: () {},
          ),
        ],
      ),
      body: Text("appbar示例"),
    );
  }
}
复制代码

导航栏部件

我们看到在materai示例中,还有一个区域为bottom。

我们可以在这个区域创建一个顶部的导航栏。

我们可以使用TabBarTabBarView这两个组件

DefaultTabController创建TabBarTabBarView的控制器,关联俩组件的桥梁

DefaultTabController必须给定 length且必须和TabBar 的tabs 的长度和TabBarView的 children的长度相同(别晕~ ~请看接下来的示例。)。

import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
   final List<Tab> myTabs =<Tab>[    
      Tab(text: "1",),
      Tab(text: "2",)
    ];
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '水平选项卡视图组件',
      home: DefaultTabController(    // 控制器关联两导航栏和内容
        length: 2,       //  长度
        child: Scaffold(
          appBar: AppBar(
            bottom: TabBar(
              tabs: myTabs   //  使用上面的变量
            ),
          ),
          body: TabBarView(
            children: myTabs.map(    // 后面介绍map的功能
              (Tab tab){
                return Center(
                  child: Text(tab.text),
                );
              }
            ).toList()
          ),
        ),
      ),
    );
  }
}

复制代码

补充内容

final List<Tab> myTabs =<Tab>[
      Tab(text: "1",),
      Tab(text: "2",)
    ];
myTabs.map(   // 将myTabs的每一个 tab传入
    (Tab tab){
    	return Center(child: Text(tab.text));   // 返回一个 Center
}).toList()     //  将全部返回情况的转化为一个列表
复制代码

一个复杂的导航栏:

import 'package:flutter/material.dart';

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

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

const items = <ItemView>[
  ItemView(title: "自驾", icon: Icons.directions_car),
  ItemView(title: "自行车", icon: Icons.directions_bike),
  ItemView(title: "船", icon: Icons.directions_boat),
  ItemView(title: "公交车", icon: Icons.directions_bus),
  ItemView(title: "地铁", icon: Icons.directions_railway),
  ItemView(title: "跑", icon: Icons.directions_run),
  ItemView(title: "火车", icon: Icons.directions_subway),
  ItemView(title: "运输", icon: Icons.directions_transit),
  ItemView(title: "走", icon: Icons.directions_walk),
];

// --------------------------------
List directionsTabs = items.map((ItemView item) {
  return Tab(
    text: item.title,
    icon: Icon(item.icon),
  );
}).toList();
//---------------------------------
// 这里最好写于tabs属性里 每次热重载时都会调用build方法(详情大家查阅以下statelessWidget的热重载模式)。如果在这里只能用大写R热重载。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: "tarbar水平列表篇",
        home: DefaultTabController(
          length: items.length,
          child: Scaffold(
            appBar: AppBar(
              bottom: TabBar(isScrollable: true, tabs: directionsTabs),
            ),
            body: TabBarView(
                children: items.map((item) {
              return Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: SelectedView(item: item));
            }).toList()),
          ),
        ));
  }
}

class SelectedView extends StatelessWidget {
  SelectedView({Key key, this.item}) : super(key: key);
  final ItemView item;
  @override
  Widget build(BuildContext context) {
    final TextStyle textStyle = Theme.of(context).textTheme.display1; //提取上一级的主题
    return Card(
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Icon(item.icon, size: 128.0, color: textStyle.color),
            Text(
              item.title,
              style: textStyle,
            )
          ],
        ),
      ),
    );
  }
}

复制代码

drawer组件

我们先看看material官方怎么说drawer组件

Drawer组件可以添加头部效果。

UserAccountsDrawerHeader

属性名 类型 说明
decoration Decoration 头部区域的decoration设置背景颜色和样式
accountName Widget 设置当前用户名
accountEmail Widget 设置当前用户的邮箱
margin EdgeInsetGeometry 设置四周间隙
OnDetailsPressed VoidCallback 回调函数。设置当用户名或者有限被点击时。触发的回调函数。
currentAccountPicture Widget 用来设置当前用户的头像
otherAccountPicture Widget 用来设置其他账号头像

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        drawer: Drawer(
          child: ListView(
            children: <Widget>[
              UserAccountsDrawerHeader(    // Hearder的位置信息
                accountName: Text("痴痴那"),
                accountEmail: Text("1161838951@qq.com"),
                currentAccountPicture: CircleAvatar(
                  backgroundImage: AssetImage("images/1.png"),
                ),
              ),
              ListTile(
                leading: CircleAvatar(
                  backgroundImage: AssetImage("images/1.png"),
                ),
                title: Text("个性装扮"),
              ),
              ListTile(
                leading: CircleAvatar(
                  backgroundImage: AssetImage("images/1.png"),
                ),
                title: Text("个性装扮"),
              ),
              ListTile(
                leading: CircleAvatar(
                  backgroundImage: AssetImage("images/1.png"),
                ),
                title: Text("个性装扮"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

复制代码

Material的路由管理

第一种方式通过

Navigator.push(context,MaterialPageRoute(builder: (context) => NewRoute())

context这里有个问题详情请看这里

juejin.im/post/5c665c…

MaterialPageRoute继承自PageRoute

/// A modal route that replaces the entire screen.
复制代码

替换整个屏幕的模态路由。

而MaterialPageRoute初始化了PageRoute中的一些属性(动画等)

class MaterialPageRoute<T> extends PageRoute<T> 
MaterialPageRoute({
    @required this.builder,
    RouteSettings settings,
    this.maintainState = true,
    bool fullscreenDialog = false,
  }) 
复制代码

Navigator是一个路由管理的组件,它提供了打开和退出路由页方法。Navigator通过一个栈来管理活动路由集合。通常当前屏幕显示的页面就是栈顶的路由。Navigator提供了一系列方法来管理路由栈。pushpop

// 第一种使用路由的方法
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //这里的上下文对象为根部
    return MaterialApp(home: HomePage());
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //这里的上下文对象是MaterialApp
    return Scaffold(
      appBar: AppBar(
        title: Text("data"),
      ),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text("home page"),
          FlatButton(
            child: Text("open new route"),
            textColor: Colors.blue,
            onPressed: () {
              //导航到新路由
              Navigator.push(      //通过Navigator.push方法
                context,
                MaterialPageRoute(builder: (context) => NewRoute()),
              );
            },
          ),
        ],
      )),
    );
  }
}

class NewRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("This is new route"),
      ),
    );
  }
}
复制代码

第二种方式

设置materialApp的routes属性 Navigator.pushNamed(context, '/second');

routes: {

	'/frist':(BuildContext context)=>FristPage(),

	'/second':(BuildContext context)=>SecondPage()

}

复制代码

一个使用pushName的例子:注意页面参数的传递以及钩子函数

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: {
        '/': (context) => MyHomePage(),
        '/a': (context) => MyHomePageA(),
        '/b': (context) =>
            MyHomePageB(text: ModalRoute.of(context).settings.arguments)
      },

      initialRoute: '/', //   初始化之后进入的页面
      onGenerateRoute: (RouteSettings routeSettings) {
        return MaterialPageRoute(builder: (context) {
          return MyHomePageC();
        }); //  MaterialPageRoute是一个控制路由的
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text("Home Page"),
            RaisedButton(
              //方式一
              child: Text("open A page"),
              onPressed: () async {
                // 异步函数
                // Navigator.pushNamed(context, '/a');   //通过注册路由表来跳转页面、
                var a = await Navigator.pushNamed(context, '/a',
                    arguments: "我是传入的数据");
                print("$a"); //    await  默认返回一个 Future 可以用then提取
                // 返回的数据
              },
            ),
            RaisedButton(
              child: Text("open B page"),
              onPressed: () {
                Navigator.of(context).pushNamed('/b', arguments: "我是传入B的参数");
              },
            ),
            RaisedButton(
              child: Text("跳转到不存在的页面"),
              onPressed: () {
                Navigator.pushNamed(context, '/c');
              },
            )
          ],
        ),
      ),
    );
  }
}

class MyHomePageA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var args = ModalRoute.of(context).settings.arguments;
    return Scaffold(
      appBar: AppBar(
          leading: IconButton(
        icon: Icon(Icons.arrow_back),
        onPressed: () {
          Navigator.pop(context, "这是传回的数据");
        },
      )),
      body: Center(
        child: Text(args),
      ),
    );
  }
}

class MyHomePageB extends StatelessWidget {
  MyHomePageB({Key key, this.text}) : super(key: key);
  final String text;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text(text),
      ),
    );
  }
}

class MyHomePageC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("123"),
      ),
    );
  }
}

复制代码

按钮和提示组件

我们用上面见到的悬浮按钮FloatingActionButton生成一个SnackBar的提示

FloatingActionButton

SnackBar

SnackBar在脚手架底部显示一个弹窗,脚手架一次最多可以显示一个SnackBar。如果在另一个SnackBar已经可见的情况下调用此功能,则当前的SnackBar将被添加到队列中并在之前的SnackBar关闭后显示。

使用Scaffold.of(context).showSnackBar(snackBar);

 const SnackBar({
    Key key,
    @required this.content,   // SnackBar的内容
    this.backgroundColor,  // 背景颜色
    this.elevation,     // 控制阴影的大小 double类型
    this.shape,         //  SnackBar的形状
    this.behavior,     	//   定义了SnackBar的位置和行为
    this.action,        // 控制SnackBar
    this.duration = _snackBarDisplayDuration,    //  SnackBar 的时间
    this.animation,     //  SnackBar 的动画
  }) 
复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final snackBar = new SnackBar(
      behavior: SnackBarBehavior.floating,
      content: new Text('删除信息'),
      action: new SnackBarAction(
          label: '撤消',
          onPressed: () {
                 // 设置一些新为信息
          }),
    );
    return MaterialApp(
        title: "按钮",
        home: Scaffold(
          appBar: AppBar(
            title: Text("按钮"),
          ),
          body: Builder(builder: (BuildContext context) {
            return RaisedButton(
              child: Text("隐藏"),
              onPressed: () {
                Scaffold.of(context).hideCurrentSnackBar();
              },
            );
          }),
          floatingActionButtonLocation:
              FloatingActionButtonLocation.centerFloat,
          floatingActionButton: Builder(builder: (BuildContext context) {
            return FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: () {
                // Scaffold.of(context).removeCurrentSnackBar();   //清除当前SnackBar
                var a = Scaffold.of(context).showSnackBar(snackBar);
                //   SnackBar(
                //   content: Text("你点击了"),
                // ));
                // a.close();   //关闭
              },
            );
          }),
        ));
  }
}

复制代码

扁平按钮

点击时有一个阴影效果

与悬浮按钮类似都是需要一个回调函数

FlatButton(onPressed: (){},child: Text("扁平悬浮按钮"),),

import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
@override
  Widget build(BuildContext context) {
    
    return MaterialApp(
      title: "扁平悬浮按钮",
      home: Scaffold(
        appBar: AppBar(

        ),
        body: Center(
          child: FlatButton(
            onPressed: (){
                // 执行一些操作
                
            },
            child: Text("扁平悬浮按钮"),
          ),
        ),
      ),
    );
  }
}
复制代码

弹出菜单

PopupMenuButton<T>

构造函数

 PopupMenuButton({
    Key key,
    @required this.itemBuilder,    //  必须不为空
    this.initialValue,
    this.onSelected,              //  当选中某项时调用此
    this.onCanceled,              
    this.tooltip,
    this.elevation,
    this.padding = const EdgeInsets.all(8.0),
    this.child,
    this.icon,
    this.offset = Offset.zero,
    this.enabled = true,
    this.shape,
    this.color,
  }) 
复制代码

弹出菜单widget使用接口与菜单项关联。

用showMenu函数显示弹出菜单,也可以使用PopupMenuButton去创建按键触发弹出菜单。

[PopupMenuEntry] 代表弹出的列表

  • [PopupMenuItem], 单个值的弹出菜单项。
  • [PopupMenuDivider], 项的分割线
  • [CheckedPopupMenuItem], 单个值的项用标记已选

实例:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());
enum ConferenceItem {
  AddMember,
  LockConference,
  ModifyLayout,
  TurnoffAll,
  TurnoffAllOF
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "弹出菜单",
      home: Scaffold(
        appBar: AppBar(
          title: Text("弹出菜单"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
            
              FlatButton(
                onPressed: () {},
                child: PopupMenuButton<ConferenceItem>(
                  child: Text("打开弹出层"),
                  onSelected: (ConferenceItem res) {
                    print(res);    // res的值为选中项的value
                  },
                  itemBuilder: (BuildContext context) =>
                      <PopupMenuEntry<ConferenceItem>>[
                    PopupMenuDivider(),
                    PopupMenuItem(
                      value: ConferenceItem.AddMember,
                      child: Text("a"),
                    ),
                    PopupMenuDivider(),
                    PopupMenuItem(
                      value: ConferenceItem.LockConference,
                      child: Text("b"),
                    ),
                    PopupMenuDivider(),
                    PopupMenuItem(
                      value: ConferenceItem.ModifyLayout,
                      child: Text("c"),
                    ),
                    PopupMenuDivider(),
                    PopupMenuItem(
                      value: ConferenceItem.TurnoffAll,
                      child: Text("d"),
                    ),
                    PopupMenuDivider(),
                    CheckedPopupMenuItem(    //
                      value: ConferenceItem.TurnoffAllOF,
                      checked: true,
                      child: Text("e"),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

复制代码

简单对话框

通常SimpleDialog(对话框)搭配SimpleDialogOption(对话框的项)一块使用

import 'package:flutter/material.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "简单对话框",
      home: Scaffold(
        appBar: AppBar(title: Text("简单对话框"),),
        body: Center(
          child: SimpleDialog(    
            title: Text("对话框"),
            children: <Widget>[
              SimpleDialogOption(
                onPressed: (){},
                child: Text("第一行信息"),
              ),
              SimpleDialogOption(
                onPressed: (){},
                child: Text("第二行信息"),
                
              )
            ],
          ),
        ),
      )
    );
  }
}

复制代码

提示对话框

AlertDialog对话框。

 const AlertDialog({
    Key key,
    this.title,                   // 标头
    this.titlePadding,            // 标头 内边距
    this.titleTextStyle,          // 标头的文本样式
    this.content,                 //  内容
    this.contentPadding = const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0),   // 内容的编剧
    this.contentTextStyle,       // 内容的样式
    this.actions,                //  按键
    this.backgroundColor,        // 背景颜色
    this.elevation,              //  z轴坐标
    this.semanticLabel,         
    this.shape,					// 边框的形状
  })
复制代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "提示对话框",
      home: Scaffold(
          appBar: AppBar(
            title: Text("提示对话框"),
          ),
          body: Center(
            child: AlertDialog(
              title: Text("提示"),
              actions: <Widget>[
                FlatButton(
                  onPressed: () {},
                  child: Text('确定'),
                ),
                FlatButton(
                  onPressed: () {},
                  child: Text('取消'),
                ),
              ],
              content: SingleChildScrollView(
                child: ListBody(
                  children: <Widget>[
                    Text("是否要删除"),
                    Text("不可恢复"),
                  ],
                ),
              ),
            ),
          )),
    );
  }
}

复制代码

文本框组件

TextField提供文本输入的组件

import "package:flutter/material.dart";
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
  
  @override
  Widget build(BuildContext context) {
  final TextEditingController controller=TextEditingController()  ;
  controller.addListener((){
    print(controller.text);
  });
    return MaterialApp(
      title: "TextField",
      home: Scaffold(
        appBar: AppBar(title: Text("data"),),
        body: Center(
          child: TextField(
            controller: controller,
            maxLength: 30,
            maxLines: 1,
            autocorrect: true,
            autofocus: true,
            textAlign: TextAlign.center,
            onChanged: (v){
              print("onchange   $v");

            },
            onSubmitted: (v){
              print("subumit $v");
            },
          ),
        ),
      ),
    );
  }
}
复制代码

控制台输出

卡片组件

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var card = SizedBox(
      height: 600,
      child: Card(
        child: Column(
          children: <Widget>[
            ListTile(
              title: Text(
                "清华大学",
                style: TextStyle(fontWeight: FontWeight.w300),
              ),
              subtitle: Text("清华大学"),
              leading: Icon(Icons.school),
            ),
            Divider(),
            ListTile(
              title: Text(
                "北京大学",
                style: TextStyle(fontWeight: FontWeight.w300),
              ),
              subtitle: Text("北京大学"),
              leading: Icon(Icons.school),
            ),
            Divider(),
            ListTile(
              title: Text(
                "浙江大学",
                style: TextStyle(fontWeight: FontWeight.w300),
              ),
              subtitle: Text("浙江大学"),
              leading: Icon(Icons.school),
            ),
          ],
        ),
      ),
    );
    return MaterialApp(
      title: "card",
      home: Scaffold(
          appBar: AppBar(
            title: Text("card"),
          ),
          body: Center(child: card)),
    );
  }
}

复制代码

参考

关注下面的标签,发现更多相似文章
评论