前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Flutter》-- 4.Flutter组件基础

《Flutter》-- 4.Flutter组件基础

作者头像
爱学习的程序媛
发布2022-04-07 16:21:53
12.4K0
发布2022-04-07 16:21:53
举报
文章被收录于专栏:学习/读书笔记学习/读书笔记

参阅书籍:

《Flutter跨平台开发入门与实践》-- 向治洪(著)

4. Flutter组件基础
4.1 Widget组件基础

Flutter开发中有一个非常重要的理念,即一切皆为组件。Flutter中Widget不仅可以表示UI元素,也可以布局元素、动画、装饰效果。

Widget不是最终显示在设备屏幕上的显示元素,而是一个描述显示元素的配置数据。Flutter中真正代表屏幕显示元素的类是Element。

在大多数场景下,可以宽泛地认为Widget树就是指UI组件树或UI渲染树。

4.1.1 StatelessWidget

StatelessWidget表示没有状态的组件,它不需要管理组件的内部状态,也无法使用setState()来改变组件的状态。

对于无状态组件的内部属性,为了防止内部成员变量的值被改变,需要使用final修饰符进行修饰。

创建无状态的组件,需要继承StatelessWidget,并重写build()。

4.1.2 StatefulWidget

StatefulWidget表示有状态的组件。当创建一个StatefulWidget组件时,同时也会创建一个State对象,StatefulWidget就是通过与State对象进行关联来管理组件状态树的。

创建有状态的组件,需要继承StatefulWidget,然后在该组件中创建状态对象,并重写build()。

4.1.3 MaterialApp

MaterialApp是Flutter开发的符合Material设计理念的Widget,可以将它类比为网页开发中的<html>标签,它提供了路由、主题色和标题等功能。

作为Flutter提供的入口Widget,MaterialApp有以下几个比较重要的参数:

1)title:String类型,表示在Android应用管理器的App上方显示的标题,对iOS设备不起作用。

2)home:Widget类型,Flutter应用默认启动后显示的第一个Widget。

3)routes:Map<String, WidgetBuilder>类型,是应用的顶级路由表。

4)theme:定义应用主题。

5)theme.primarySwatch:应用的主题色。

6)theme.primaryColor:单独设置导航栏的背景色。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material Components',
      home: FirstPage(),
      routes: <String, WidgetBuilder> {
        '/first': (BuildContext context) => FirstPage(),
        '/second': (BuildContext context) => SecondPage(),
      },
      initialRoute: '/first',
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('第一页')
      ),
      body: Padding(
        padding: EdgeInsets.all(30.0),
        child: MaterialButton(
          color: Colors.green,
          textColor: Colors.white,
          child: Text('跳转到第二页'),
          onPressed: () {
            Navigator.pushNamed(context, '/second');
          },
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('第二页')
      ),
      body: Padding(
        padding: EdgeInsets.all(30.0),
        child: MaterialButton(
          color: Colors.green,
          textColor: Colors.white,
          child: Text('返回第一页'),
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),
      ),
    );
  }
}

示例效果:

4.1.4 AppBar

AppBar是Flutter应用的顶部导航栏组件,可以用来控制路由、标题和溢出下拉菜单。

AppBar的基本属性如下:

1)leading:标题左边的图标按钮,默认是一个返回箭头样式的按钮。

2)title:导航栏标题。

3)actions:右边的动作区域中可放置多个组件,可以是图标或者文字。

4)flexibleSpace:位于标题下面的空白空间。

5)bottom:位于导航栏底部的自定义组件。

6)elevation:控制下方阴影栏的坐标。

7)backgroundColor:导航栏的颜色,默认值为ThemeData.primarycolor(主题颜色)。

8)brightness:导航栏材质的亮度。

9)textTheme:文本主题设置。

10)primary:导航栏是否显示在任务栏顶部。

11)centerTitle:标题是否居中显示。

12)titleSpacing:标题的间距。

13)toolbarOpacity:导航栏透明度,1.0表示完全不透明,0.0表示完全透明。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class AppBarSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: const Text('Basic AppBar'),
          centerTitle: true,
          actions: <Widget>[
            new IconButton(
              icon: Icon(choices[0].icon),
              onPressed: null,
            ),
            new IconButton(
              icon: new Icon(choices[1].icon),
              onPressed: null,
            ),
            new IconButton(
              icon: new Icon(choices[2].icon),
              onPressed: null,
            ),
            new PopupMenuButton<Choice>(
              itemBuilder: (BuildContext context) {
                return choices.map((Choice choice) {
                  return new PopupMenuItem<Choice>(
                    value: choice,
                    child: new Text(choice.title)
                  );
                }).toList();
              },
            ),
          ],
        ),
        body: new Padding(
          padding: const EdgeInsets.all(16.0),
          child: new ChoiceCard(choices[0].title, choices[0].icon),
        ),
      ),
    );
  }
}

class ChoiceCard extends StatelessWidget {
  final String title;
  final IconData icon;
  const ChoiceCard(this.title, this.icon);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              title,
              style: TextStyle(
                fontSize: 60
              ),
            ),
            Icon(
              icon,
              size: 100
            ),
          ],
        ),
      ),
    );
  }
}

class Choice {
  final String title;
  final IconData icon;
  const Choice({this.title, this.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),
];

示例效果:

4.1.5 Scaffold

Scaffold是具有Material布局风格的Widget,它被设计为MaterialApp的顶级容器组件,可以自动填充可用的屏幕空间,占据整个窗口或者设备屏幕。

Scaffold常用的属性:

1)appBar:用于设置顶部的标题栏,不设置就不显示;

2)body:Widget类型,显示Scaffold内容的主要容器。

3)bottomNavigationBar:设置Scaffold的底部导航栏,items的数量必须大于2。

4)drawer:设置抽屉效果。

5)floatingActionButton:设置位于右下角的按钮。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class ScaffoldSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('首页'),
        ),
        bottomNavigationBar: BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          currentIndex: 1,
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.account_balance),
              title: Text('银行'),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.contacts),
              title: Text('联系人'),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.library_music),
              title: Text('音乐'),
            ),
          ],
         ),
      ),
    );
  }
}

示例效果:

4.2 状态管理基础知识

在Flutter开发中,Widget状态管理主要分为3种场景,即Widget自身状态管理、子Widget状态管理、父Widget和子Widget都存在的状态管理。

具体选择哪种状态管理,可以参考如下基本原则:

1)如果状态是有关界面外观效果的(如颜色、动画等),最好由Widget自身管理;

2)如果状态是用户数据(如复选框的选中状态、滑块位置等),最好由父Widget管理;

3)如果某一个状态是不同Widget共享的,最好由它们共同的父Widget管理。

4.2.1 状态生命周期

1)初始化阶段

构造函数:生命周期的起点,通过调用createState()来创建一个状态。

initState():在状态组件被插入视图树时调用,在状态组件的生命周期中只被调用一次。

didChangeDependencies():用来处理状态组件依赖关系变化,会在initState()调用结束后被调用。

build():用于构建视图。在build()中,需要根据父Widget传递过来的初始化配置数据及状态组件的当前状态,创建一个Widget然后返回。

2)更新阶段

setState():当状态数据发生变化时,通过调用setState()告诉系统使用更新后数据重构视图。

didChangeDependencies():状态组件的依赖关系发生变化后,Flutter会回调该函数,随后触发组件的构建操作。

didUpdateWidget():当组件的配置发生变化或执行热重载时,系统会回调该函数更新视图。

3)销毁阶段

deactivate():当组件的可见状态发生变化时,deactivate()会被调用,此时状态组件会被暂时从视图树中移除。

dispose():当状态组件需要被永久地从视图树中移除时,调用dispose()。调用dispose()后,组件会被销毁,在调用dispose()之前可以执行资源释放、移除监听、清理环境等工作。

4.2.2 自身状态管理

改变Widget自身的状态时使用setState(),调用setState()后视图会执行重绘操作。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class TapboxA extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _TapboxAState();
  }
}

class _TapboxAState extends State<TapboxA> {
  bool _active = false;
  void _handleTap() {
    setState(() {
      _active = !_active;
    });
  }
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: _handleTap,
      child: new Container(
        child: new Center(
          child: new Text(
            _active ? 'Acitive' : 'Inactive',
            style: new TextStyle(
              fontSize: 32,
              color: Colors.white
            ),
            textDirection: TextDirection.ltr,
          ),
        ),
        width: 200,
        height: 200,
        decoration: new BoxDecoration(
          color: _active ? Colors.lightGreen[700] : Colors.grey[600],
        ),
      ),
    );
  }
}

示例效果:

4.2.3 父子组件状态管理

在此种情况下,子Widget往往是一个无状态的组件,父Widget只需要告诉子Widget何时更新即可。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class TapboxA extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _TapboxAState();
  }
}

class _TapboxAState extends State<TapboxA> {
  bool _active = false;
  void _onChanged(bool active) {
    setState(() {
      _active = active;
    });
  }
  Widget build(BuildContext context) {
    return Container(
      child: new TapboxB(active: _active, onChanged: _onChanged)
    );
  }
}

class TapboxB extends StatelessWidget {
  final bool active;
  final ValueChanged<bool> onChanged;
  TapboxB({Key key, this.active: false, @required this.onChanged}): super(key: key);
  void _handleTap() {
    onChanged(!active);
  }
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _handleTap,
      child: Container(
        child: Center(
          child: Text(
            active ? 'Active' : 'Inactive',
            style: new TextStyle(
              fontSize: 32,
              color: Colors.white
            ),
            textDirection: TextDirection.ltr,
          ),
        ),
        width: 200,
        height: 200,
        decoration: new BoxDecoration(
          color: active ? Colors.lightGreen[700] : Colors.grey[600],
        ),
      ),
    );
  }
}

示例效果:

4.2.4 混合状态管理

在混合状态管理模式下,子组件自身管理一些内部状态,父组件管理其他外部状态。在此种模式下,子组件使用构造函数接收父组件传递的状态,并使用回调函数返回子组件内部的状态。

示例代码:

代码语言:javascript
复制
//TapboxC.dart

import 'package:flutter/material.dart';

class TapboxC extends StatefulWidget {
  final bool active;
  final ValueChanged<bool> onChanged;
  TapboxC({Key key, this.active: false, @required this.onChanged}): super(key: key);
  TapboxCState createState() => new TapboxCState();
}

class TapboxCState extends State<TapboxC> {
  bool _highlight = false;
  void _handleTapDown(TapDownDetails details) {
    setState((){
      _highlight = true;
    });
  }
  void _handleTapUp(TapUpDetails details) {
     setState((){
      _highlight = false;
    });
  }
  void _handleTapCancel() {
    setState(() {
      _highlight = false;
    });
  }
  void _handleTap() {
    widget.onChanged(!widget.active);
  }
  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTapDown: _handleTapDown,
      onTapUp: _handleTapUp,
      onTap: _handleTap,
      onTapCancel: _handleTapCancel,
      child: new Container(
        child: new Center(
          child: new Text(
            widget.active ? 'Active' : 'Inactive',
            style: new TextStyle(fontSize: 32, color: Colors.white),
            textDirection: TextDirection.ltr,
          ),
        ),
        width: 200,
        height: 200,
        decoration: new BoxDecoration(
          color: widget.active ? Colors.lightGreen[700] : Colors.grey[600], 
          border: _highlight ? Border.all(color: Colors.teal[700], width: 10) : null,
        ),
      )
    );
  }
}
代码语言:javascript
复制
//main.dart

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

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

class ParentWidget extends StatefulWidget {
  ParentWidgetState createState() => new ParentWidgetState();
}

class ParentWidgetState extends State<ParentWidget> {
  bool _active = false;
  void _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }
  @override
  Widget build(BuildContext context) {
    return new Container(
      child: new TapboxC(
        active: _active,
        onChanged: _handleTapboxChanged,
      )
    );
  }
}

4.3 基础组件

4.3.1 文本组件

Text组件常见属性:

textAlign属性用于控制文本的对齐方式,取值有6种:

TextAlign.left:左对齐;

TextAlign.right:右对齐;

TextAlign.center:居中对齐;

TextAlign.start:文字开始的方向对齐;

TextAlign.end:文字开始的相反方向对齐;

TextAlign.justify:两端对齐。

textDirection属性用于控制文字的显示方向,取值有2种:

TextDirection.ltr:文字方向从左到右;

TextDirection.rtl:文字方向从右到左。

overflow属性用于表示文本的截断方式,取值有3种:

TextOverflow.ellipsis:多余文本截断后以省略符表示;

TextOverflow.clip:剪切多余文本,多余文本不显示;

TextOverflow.fade:将多余的文本设为透明。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class TextWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Text组件',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Text组件'),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              Text('默认样式'),
              Text(
                '红色,20号字体',
                style: TextStyle(
                  color: const Color(0xffff0000),
                  fontSize: 20
                ),
              ),
              Text(
                '20号字体,中划线',
                style: TextStyle(
                  decoration: TextDecoration.lineThrough,
                  fontSize: 20
                )
              ),
              Text(
                '20号字体,粗体,倾斜',
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontStyle: FontStyle.italic,
                  fontSize: 20
                )
              ),
              Text(
                '红色,20号字体,文字装饰',
                style: TextStyle(
                  decoration: TextDecoration.underline,
                  decorationColor: Colors.red,
                  decorationStyle: TextDecorationStyle.wavy,
                  fontSize: 20
                )
              )
            ]
          ) 
        ),
      )
    );
  }
}

示例效果:

除了使用Flutter官方提供的默认字体外,还可以使用第三方字体。使用第三方字体前,需要先在pubspec.yaml配置文件中进行声明,然后使用TextStyle属性引入第三方字体。

4.3.2 按钮组件

Materail组件库中常见的按钮组件:

RaisedButton:默认是带有阴影和灰色背景的按钮,按下后阴影会变大;

FlatButton:默认是背景透明并不带阴影的按钮,按下后会有背景色;

OutlineButton:默认是一个带有边框、不带阴影且背景透明的按钮,按下后边框颜色会变亮,同时会出现背景和阴影效果;

IconButton:一个可点击的图标按钮,不支持文字,默认没有背景,点击后会出现背景。

所有Materail组件库的按钮都有两个相同点:一是按下时会有水波动画,另一个是都有一个onPressed属性来设置单击回调。

RaisedButton、FlatButton和OutlineButton等Material按钮组件都有一个图标构造函数,可以使用它来创建带图标的按钮。

按钮组件的常见属性:

其中onPressed属性是必须的。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class ButtonWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Button 组件')),
        body: Center(
          child: Column(
            children: <Widget>[
              FlatButton(
                child: Text('Flat'),
                onPressed: () => print('FlatButton pressed')
              ),
              RaisedButton(
                child: Text('Raised'),
                onPressed: () => print('RaisedButton pressed'),
              ),
              FloatingActionButton(
                child: Text('Float'),
                onPressed: () => print('FloatingActionButton pressed')
              ),
              OutlineButton(
                child: Text('Outline'),
                onPressed: () => print('OutlineButton pressed')
              ),
              IconButton(
                icon: Icon(Icons.thumb_up),
                onPressed: () => print('IconButton pressed')
              )
            ]
          )
        )
      )
    );
  }
}

示例效果:

4.3.3 图片组件

可以使用以下方式来加载不同形式的图片:

Image:通过ImageProvider来加载图片。

Image.asset:用来加载本地的图片。

Image.file:用来加载本地.file文件类型的图片。

Image.network:用来加载网络图片;

Image.memory:用来加载内存缓存的图片。

Image组件常见属性:

fit属性用于指定图片的填充模式,取值如下:

BoxFit.fill:全图显示,图片有可能被拉伸,造成图片变形;

BoxFit.contain:全图显示,图片不会变形,超出显示空间的部分会被剪裁;

BoxFit.cover:默认填充规则,在保证长宽比不变的情况下缩放以适应当前显示空间,图片不会变形;

BoxFit.fitWidth:从宽度上充满空间,高度会按比例缩放,图片不会变形,超出显示空间部分会被剪裁;

BoxFit.fitHeight:从高度上充满空间,宽度会按比例缩放,图片不会变形,超出显示空间部分会被剪裁;

BoxFit.scaleDown:与BoxFit.contain的效果差不多,但此属性会缩小图像以确保图像位于显示空间内;

BoxFit.none:没有填充策略,按图片原始大小显示。

示例:加载本地图片

代码语言:javascript
复制
//pubspec.yaml

...
flutter:
...
assets: 
    - images/test.jpg
...
代码语言:javascript
复制
//main.dart

import 'package:flutter/material.dart';

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

class ImageWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Image 组件')),
        body: Center(
          child: Image.asset('images/test.jpg')
        )
      )
    );
  }
}

示例效果:

4.3.4 图标组件

常用的图标组件:

IconButton:可交互的Icon组件;

Icons:Flutter自带的Icon组件集合;

IconTheme:Icon组件的主题;

ImageIcon:通过AssetImages或者其他图片显示Icon组件。

Icon组件常见属性:

Android支持系统自带的图标,mipmap文件中存放的就是Icon类型的图标。

Flutter默认包含了一套Materail Design的字体图标,使用前需要在pubspec.yaml文件中进行如下配置:

代码语言:javascript
复制
...
flutter:
  Uses-material-design: true
  ...

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class IconWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    String icons = '';
    icons += '\uE914';
    icons += ' \uE000';
    icons += ' \uE90D';
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primaryColor: Colors.blue),
      home: Scaffold(
        appBar: AppBar(title: Text('Icon 组件')),
        body: Text(
          icons,
          style: TextStyle(
            fontFamily: 'MaterialIcons',
            fontSize: 40,
            color: Colors.green
          )
        )
      )
    );
  }
}

示例效果:

4.3.5 输入框组件

常见属性:

controller:输入框控制器,通过它可以获取和设置输入框的内容以及监听文本内容的改变。如果没有提供controller,则TextField组件内部会自动创建一个。

focusNode:用于控制TextField组件是否获取输入焦点,它是用户和键盘交互的一种常见方式。

decoration:用于控制TextField组件的外观显示,如提示文本、背景颜色和边框。

textAlign:输入框内文本在水平方向的对齐方式。

textDirection:输入框内文本的方向。

keyboardType:用于设置该输入框默认的键盘输入类型。

textInputAction:回车键为动作按钮图标。

style:输入框的样式。

autofocus:是否自动获取焦点,默认为false。

obscureText:是否隐藏正在编辑的文本内容。

maxLines:输入框文本的最大行数,默认为1.

maxLength:输入框中允许的最大字符数。

onChange:输入框内容改变时的回调函数。

onEditingComplete:输入框输入完成时触发,不会返回输入的内容。

onSubmitted:输入框输入完成时触发,会返回输入的内容。

inputFormatters:指定输入格式,当用户输入的内容发生改变时,会根据指定的格式来进行校验。

enabled:是否禁用输入框。

enableInteractiveSelection:是否启用交互式选择,为true时表示长选中文字,并弹出cut、copy、paste菜单。

keyboardAppearance:设置键盘的亮度模式,只能在iOS上使用。

onTap:TextField组件的点击事件。

buildCounter:自定义InputDecorator.counter小部件的回调实现。

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class TextFieldWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('TextField 组件')),
        body: Column(
          children: <Widget>[
            TextField(
              autofocus: true,
              decoration: InputDecoration(
                hintText: '请输入用户名或邮箱',
                prefixIcon: Icon(Icons.person)
              ),
              onChanged: (v) => print('onChange: $v'),
            ),
            TextField(
              decoration: InputDecoration(
                hintText: '请输入登录密码',
                prefixIcon: Icon(Icons.lock),
              ),
              obscureText: true,
            ),
            SizedBox(height: 15),
            Container(
              height: 46,
              width: 300,
              child: RaisedButton(
                color: Colors.blue,
                textColor: Colors.white,
                child: new Text('登录'),
                onPressed: () {}
              )
            )
          ],
        )
      )
    );
  }
}

示例效果:

4.3.6 表单组件

Form是一个包含表单元素的表单组件,可以用来对输入的信息进行校验。表单组件由FormField及其子类构成,最常用的表单组件有DropdownButtonFormField和TextFormField两个。

表单组件是一个有状态的组件,FormState就是表单的状态,可以通过Form.of()或GlobalKey获取组件的状态。

Form组件常见属性:

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class FormWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return FormWidgetState();
  }
}

class FormWidgetState extends State<FormWidget> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primaryColor: Colors.blue),
      home: Scaffold(
        appBar: AppBar(title: Text('Form 组件')),
        body: Form(
          key: _formKey,
          child: Column(
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(
                  hintText: '用户名',
                  icon: Icon(Icons.person)
                ),
                validator: (value) {
                  if(value.length <= 5) {
                    return '用户名必须大于5个字符';
                  }
                },
              ),
              TextFormField(
                decoration: InputDecoration(
                  hintText: '密码',
                  icon: Icon(Icons.lock)
                ),
                validator: (value) {
                  if(value.length <= 8) {
                    return '密码必须大于8个字符';
                  }
                },
              ),
              SizedBox(height: 15),
              RaisedButton(
                padding: EdgeInsets.all(15),
                child: Text('登录'),
                color: Theme.of(context).primaryColor,
                textColor: Colors.white,
                onPressed: () {
                  if(_formKey.currentState.validate()) {
                    _formKey.currentState.save();
                  }
                },
              )
            ],
          )
        )
      )
    );
  }
}

示例效果:

4.4 容器组件

Container是Flutter提供的容器组件,可以包含一个子组件,常用的属性如下:

示例代码:

代码语言:javascript
复制
import 'package:flutter/material.dart';

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

class ContainerWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 容器组件',
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter 容器组件')),
        body: Container(
          margin: EdgeInsets.only(top: 30,  left: 120),
          constraints: BoxConstraints.tightFor(width: 200, height: 150),
          decoration: BoxDecoration(
            gradient: RadialGradient(
              colors: [Colors.red, Colors.orange],
              center: Alignment.topLeft,
              radius: .98
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.black54,
                offset: Offset(2, 2),
                blurRadius: 4
              )
            ]
          ),
          transform: Matrix4.rotationZ(.2),
          alignment: Alignment.center,
          child: Text(
            '520',
            style: TextStyle(fontSize: 40, color: Colors.white),
          ),
        )
      )
    );
  }
}

示例效果:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱学习的程序媛 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 4. Flutter组件基础
    • 4.1 Widget组件基础
      • 4.1.1 StatelessWidget
      • 4.1.2 StatefulWidget
      • 4.1.3 MaterialApp
      • 4.1.4 AppBar
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档