【Flutter】之自带组件(覆盖 80%场景使用的基础组件,带完整示例)

2,681 阅读19分钟

前言

在之前的文章中讲到关于Dart语言和 Flutter 周边的安装,那么现在我们全部就已经就绪,现在就可以开始开发了。本篇文章是分享一下关于Flutter 自带的组件,因为Flutter 官方文档使用的是英文,市面上一些关于Flutter的介绍文章也都较为碎片化,只能一边查一边写,很浪费时间,所以我就将我用到的都总结在这里,随着我用的越多,文章也会持续更新,欢迎各位监督。更新日期:2022-12-02

UI 样式用 Material,还是 Cupertino

Flutter 中包含两套风格的组件,分别是 MaterialCupertinoCupertinoiOS风格的组件,命名都带 Cupertino 前缀,比如 CupertinoSliderCupertinoDatePicker 等, Material Design 是由 Google 推出,旨在为手机、平板电脑、台式机和“其他平台”提供更一致、更广泛的“外观和感觉”。

本篇着重分享就 Material 类型的样式!!!

Material 风格使用

  1. 导入
import 'package:flutter/material.dart';
  1. 添加
void main() => runApp(new App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp();
  }
}

MaterialApp

一个MaterialApp一般包含如下两部分:

MaterialApp(
    title: 'Flutter',
    home: new Scaffold(
    ),
)

其中home是我们App中可以看见的元素部分。

Scaffold 框架

ScaffoldMaterial library 中提供的一个 widget,它提供了最基本的页面布局结构,有导航栏、标题、滑出的抽屉、底部导航、背景颜色以及最重要的主屏幕body等。widget 树可以很复杂。简单的例子如下:

Scaffold(
        appBar: AppBar(title: const Text('标题')),
        body: const Center(
          child: Text('内容'),
       ))...

效果如下:

image.png

注意: 当一个页面只可以用一个Scaffold,避免嵌套组件多处使用。


第一个hello word

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('hellow,world'),
        ),
        body: const Center(child: Text('hellow world imook')),
      ),
    );
  }
}

image.png

AppBar 顶部导航栏

  • title : 顶部的名称
  • elevation: 阴影
  • centerTitle:是否居中
  • leading: 左侧的操作按钮,平常用作返回按钮
  • actions: 右侧的操作按钮,可以是多个
  • backgroundColor:更改appbar的主题颜色
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('标题'),
          elevation: 10.0,
          centerTitle: true,
          leading: const BackButton(),
          actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.menu),
              onPressed: () {},
            ),
            IconButton(
              icon: const Icon(Icons.add),
              onPressed: () {},
            )
          ],
        ),
        body: const Center(
          child: Text('内容'),
        ));
  }
}

image.png

appbar的主题颜色默认是蓝色,当然也是可以更改的:

image.png


Text 文本显示组件

最常用的组件,没有之一,一般作为子组件用在需要文字显示的地方。

最基础的使用:

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: Text('内容'),
    ));
  }
}

image.png

style 文字样式

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: Text(
        '内容',
        style: TextStyle(
          color: Colors.red
        ),
      ),
    ));
  }
}

image.png

---

添加方式如上,以下示例将用伪代码代替,为了看起来方便,下面字体都加大了:


fontSize 字体大小

 style: TextStyle(
    fontSize: 30.0,
),

image.png


fontStyle 字体样式

  • FontStyle.italic 斜体
 style: TextStyle(
    fontSize: 30.0,
    fontStyle: FontStyle.italic,
),

image.png

  • FontStyle.normal 普通,无样式
 style: TextStyle(
    fontSize: 30.0,
    fontStyle: FontStyle.normal,
),

image.png


fontWeight 字体粗细

  • FontWeight.bold 加粗,等同于 FontWeight.w700
 style: TextStyle(
    fontSize: 30.0,
    fontWeight: FontWeight.bold,
),

image.png


  • FontWeight.normal 普通样式,无加粗
 style: TextStyle(
    fontSize: 30.0,
    fontWeight: FontWeight.normal,
),

image.png


除了上面的两种模式,FontWeight 还有从w100 -- w900的枚举,供我们使用:


  • FontWeight.w100 最细
 style: TextStyle(
    fontSize: 30.0,
    fontWeight: FontWeight.w100,
),

image.png

  • FontWeight.w900 最粗,要比FontWeight.bold还要粗
 style: TextStyle(
    fontSize: 30.0,
    fontWeight: FontWeight.w900,
),

image.png


decoration 装饰器

顾名思义就是给字体加一些额外的样式,下划线,删除线等。

  • TextDecoration.lineThrough 删除线
 style: TextStyle(
    fontSize: 30.0,
    decoration: TextDecoration.lineThrough,
),

image.png


  • TextDecoration.overline 文字上划线
 style: TextStyle(
    fontSize: 30.0,
    decoration: TextDecoration.overline,
),

image.png


  • TextDecoration.underline 文字下划线
 style: TextStyle(
    fontSize: 30.0,
    decoration: TextDecoration.underline,
),

image.png


  • TextDecoration.none 无任何装饰
 style: TextStyle(
    fontSize: 30.0,
    decoration: TextDecoration.none,
),

image.png


以下介绍的几个属性并不在style里面,而是写在外面的属性

textAlign 文字对齐方式

  • TextAlign.right 右对齐
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
      width: 200.0,
      height: 200.0,
      color: Colors.pink,
      margin: const EdgeInsets.only(top: 100),
      child: const Text(
        '内容',
        style: TextStyle(
          fontSize: 30.0,
        ),
        textAlign: TextAlign.right,
      ),
    ));
  }
}

image.png


  • TextAlign.left 左对齐
 textAlign: TextAlign.left

image.png


  • TextAlign.center 左对齐
 textAlign: TextAlign.center

image.png


startend 取决于TextDirection,如果是TextDirection.ltr,开始是左边,如果TextDirection.rtl,开始是右边

  • TextAlign.start 以开始位置为对齐方式
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          height: 50.0,
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world China,hellow world China hellow world China hellow world China hellow world China hellow world Chinahellow world Chinahellow world Chinahellow world iChina',
            textDirection: TextDirection.rtl,
            textAlign: TextAlign.start,
            style: TextStyle(
              fontSize: 20.0,
              color: Colors.pink,
            ),
          )),
    );
  }
}

image.png


  • TextAlign.end 以结束位置为对齐方式
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          height: 50.0,
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world China,hellow world China hellow world China hellow world China hellow world China hellow world Chinahellow world Chinahellow world Chinahellow world iChina',
            textDirection: TextDirection.rtl,
            textAlign: TextAlign.end,
            style: TextStyle(
              fontSize: 20.0,
              color: Colors.pink,
            ),
          )),
    );
  }
}

image.png


  • TextAlign.justify 两端对齐方式

不要给父级定义宽高,不然不生效,而且两端对齐只对首行生效

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world China,hellow world China hellow world Chinahellow world Chinahellow world Chinahellow world iChina',
            textAlign: TextAlign.justify,
            style: TextStyle(
              fontSize: 20.0,
              color: Colors.pink,
            ),
          )),
    );
  }
}

image.png


maxLines 最大行数

设置当前显示最多的行数

 import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world China,hellow world China hellow world China hellow world China hellow world China hellow world Chinahellow world Chinahellow world Chinahellow world iChina',
            maxLines: 2,
            style: TextStyle(
              fontSize: 20.0,
              color: Colors.pink,
            ),
          )),
    );
  }
}

image.png


overflow 文本溢出

  • TextOverflow.ellipsis 超出内容省略显示
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world China,hellow world China hellow world China hellow world China hellow world China hellow world Chinahellow world Chinahellow world Chinahellow world iChina',
            overflow: TextOverflow.ellipsis,
            style: TextStyle(
              fontSize: 20.0,
              color: Colors.pink,
            ),
          )),
    );
  }
}

image.png


  • TextOverflow.fade 超出内容淡入透明
 overflow: TextOverflow.fade

image.png


  • TextOverflow.visible 默认显示
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          height: 50.0,
          color: Colors.amber,
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world China,hellow world China hellow world China hellow world China hellow world China hellow world Chinahellow world Chinahellow world Chinahellow world iChina',
            overflow: TextOverflow.visible,
            style: TextStyle(
              fontSize: 20.0,
              color: Colors.pink,
            ),
          )),
    );
  }
}

image.png

  • TextOverflow.clip 对超出部分进行裁切
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          height: 50.0,
          color: Colors.amber,
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world China,hellow world China hellow world China hellow world China hellow world China hellow world Chinahellow world Chinahellow world Chinahellow world iChina',
            overflow: TextOverflow.clip,
            style: TextStyle(
              fontSize: 20.0,
              color: Colors.pink,
            ),
          )),
    );
  }
}

image.png


img 图片

加入的几种形式:

asset  加载资源图片,会使打包时包体过大

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          alignment: Alignment.topCenter,
          margin: const EdgeInsets.only(top: 100),
          child: Image.asset(
            'assets/images/rongxin_icon.png',
            height: 200.0,
            width: 300.0,
            fit: BoxFit.fill,
          )),
    );
  }
}

image.png

network  网络资源图片,经常换的或者动态的图片

import 'package:flutter/material.dart';

// 扁平化风格

void main() => runApp(const APage());

class APage extends StatelessWidget {
  const APage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'cont',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('img'),
        ),
        body: Center(
            child: Container(
          child: Image.network(
            'https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_e835568.png',
            scale: 1.5,
            // fit: BoxFit.fitWidth, // 图片充满样式
            // color: Colors.green,
            // colorBlendMode: BlendMode.srcATop, // 图片混合叠加模式
            repeat: ImageRepeat.repeatX, // 图片重复样式
          ),
          width: 300.0,
          height: 200.0,
          color: Colors.lightGreen,
        )),
      ),
    );
  }
}

image.png

  • file 本地图片,比如相机照相后的图片预览
  • memory  加载到内存中的图片,Uint8List

Icon 图标

更多图标地址:跳转链接

image.png

示例:

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: Icon(
        Icons.fingerprint,
        size: 40,
        color: Colors.red,
        semanticLabel: 'fingerprint',
      ),
    ));
  }
}

image.png


Button

根据用途和使用场景不同,分为多个不同的button 类型,整理中也发现有些button 已经不维护了,当然也有代替它的使用

废弃的Button       代替的Button

RaisedButton  =>  ElevatedButton
 
FlatButton    =>  TextButton

OutlineButton =>  OutlinedButton

ElevatedButton 按钮

ElevatedButton是一个凸起的Material矩形按钮,可以使用提升的按钮为原本基本平坦的布局添加维度,例如在长列表中,或在广阔的空间中。避免在已经提升的内容(如对话框或卡片)上使用提升按钮

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          margin: const EdgeInsets.all(40.0),
          child: ElevatedButton(
            child: const Text('按钮'),
            onPressed: () {
              print('点击事件');
            },
          )),
    );
  }
}

image.png


IconButton 图标按钮

为配合展示,给容器加了宽高和背景,这些不是按钮的,按钮只有图标

import 'package:flutter/material.dart';
import 'package:ytxim_flutter_sdk_example/resource/icons/iconfont_line.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        width: 200.0,
        height: 200.0,
        color: Colors.blue,
        margin: const EdgeInsets.all(40.0),
        child: IconButton(
          icon: const Icon(
            IconFontLine.icon_plus,
            color: Colors.white,
            size: 30.0,
          ),
          onPressed: () => {print('22')},
        ),
      ),
    );
  }
}

image.png


TextButton 文字按钮

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        margin: const EdgeInsets.all(40.0),
        child: TextButton(
            onPressed: () {
              print('点击事件');
            },
            child: const Text('确定'),
            style: ButtonStyle(
                textStyle: MaterialStateProperty.all(
                    const TextStyle(color: Colors.blue, fontSize: 20.0)))),
      ),
    );
  }
}

image.png


OutlinedButton 带边框的按钮

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
            margin: const EdgeInsets.only(top: 100.0),
            child: OutlinedButton(
              child: const Text('Button'),
              onPressed: () {
                print('点击事件');
              },
            )));
  }
}

image.png


TextField 输入框

import 'package:flutter/material.dart';

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

  TextEditingController contr = TextEditingController();
  final focusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(),
    )));
  }
}

image.png

autofocus 获取焦点

import 'package:flutter/material.dart';

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

  TextEditingController contr = TextEditingController();
  final focusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(
        autofocus: true,
      ),
    )));
  }
}

image.png


maxLength 内容最长字数,字数统计

import 'package:flutter/material.dart';

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

  TextEditingController contr = TextEditingController();
  final focusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(
        autofocus: true,
        maxLength: 20,
      ),
    )));
  }
}

image.png


  • minLines 最小行数 maxLines 最大行数
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: SizedBox(
        width: 250.0,
        child: TextField(
          minLines: 1,
          maxLines: 3,
        ),
      ),
    ));
  }
}

image.png


decoration 装饰器

  • hintText 当输入框为空时的提示,不为空时不显示,hintStylehintText的文字样式
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(
        decoration: InputDecoration(
          hintText: '请输入',
          hintStyle: TextStyle(fontSize: 20.0, color: Colors.blue),
        ),
      ),
    )));
  }
}

image.png


  • error 错误样式
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(
        decoration: InputDecoration(
          errorText: '邮箱输入错误',
          errorStyle: TextStyle(fontSize: 20),
          errorMaxLines: 1,
          errorBorder:
              OutlineInputBorder(borderSide: BorderSide(color: Colors.red)),
        ),
      ),
    )));
  }
}

image.png


  • labelText 标签

当输入框是空而且没有焦点时,labelText显示在输入框上边,当获取焦点或者不为空时labelText往上移动一点,labelStyle参数表示文本样式,具体参考TextStyle

import 'package:flutter/material.dart';

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

  TextEditingController contr = TextEditingController();
  final focusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(
        decoration: InputDecoration(
          labelText: '邮箱:',
          labelStyle: TextStyle(fontSize: 20.0, color: Colors.blue),
        ),
      ),
    )));
  }
}

获取焦点前

image.png

获取焦点后:

image.png


  • prefix 前缀
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(
        decoration: InputDecoration(prefixIcon: Icon(Icons.person)),
      ),
    )));
  }
}

image.png


  • suffix 后缀,接收一个widgetsuffixIcon 接收一个Iconwidget
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
            child: SizedBox(
      width: 200.0,
      child: TextField(
        decoration: InputDecoration(
          suffixIcon: Icon(Icons.fingerprint),
          suffix: Text('.com'),
        ),
      ),
    )));
  }
}

image.png


  • filled 重写输入框

filledtrue时,输入框将会被fillColor填充

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: SizedBox(
        width: 250.0,
        child: TextField(
            decoration: InputDecoration(
          fillColor: Color(0x30cccccc),
          filled: true,
          enabledBorder: OutlineInputBorder(
              borderSide: BorderSide(color: Color(0x00FF0000)),
              borderRadius: BorderRadius.all(Radius.circular(100))),
          hintText: '身份证号/手机号/邮箱',
          focusedBorder: OutlineInputBorder(
              borderSide: BorderSide(color: Color(0x00000000)),
              borderRadius: BorderRadius.all(Radius.circular(100))),
        )),
      ),
    ));
  }
}

image.png

  • border 边框,默认是带下边框,可以设置不带边框
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
        body: Center(
      child: SizedBox(
        width: 250.0,
        child: TextField(
          decoration: InputDecoration(
            border: InputBorder.none,
          ),
          // autofocus: true,
        ),
      ),
    ));
  }
}

image.png


controller 控制器

控制器可以同步拿到输入时回调,用在输入时校验

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  Index({Key? key}) : super(key: key);
  TextEditingController resCtrl = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: SizedBox(
        width: 250.0,
        child: TextField(
          controller: resCtrl,
          autofocus: true,
          onChanged: (value) {
            resCtrl.text = value;
            print(value);
          },
        ),
      ),
    ));
  }
}

image.png


Container 容器组件

在容器组件里最常用的则是Container,类似 div

  • width
  • height
  • color 容器填充颜色
  • child 容器的内容区域
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          color: Colors.lightBlue,
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


alignment 内容对齐方式,以容器为框,进行对齐

  • Alignment.topCenter 顶部居中对齐

当前效果基本等同于 textAlign: TextAlign.center

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          color: Colors.lightBlue,
          alignment: Alignment.topCenter,
          margin: const EdgeInsets.only(top: 100),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • Alignment.topLeft 顶部左对齐
  alignment: Alignment.topLeft,

image.png


  • Alignment.topRight 顶部右对齐
  alignment: Alignment.topRight,

image.png


  • Alignment.center 上下左右居中
  alignment: Alignment.center,

image.png


  • Alignment.centerLeft 上下居中左对齐
  alignment: Alignment.centerLeft,

image.png


  • Alignment.centerRight 上下居中右对齐
  alignment: Alignment.centerRight,

image.png


  • Alignment.bottomCenter 左右居中+底对齐
  alignment: Alignment.bottomCenter,

image.png


  • Alignment.bottomLeft 左对齐+底对齐
  alignment: Alignment.bottomLeft,

image.png


  • Alignment.bottomRight 右对齐+底对齐
  alignment: Alignment.bottomRight,

image.png


margin && padding 外边距、内边距

在边距赋值处需要用的 EdgeInsets,那就先来看一下 EdgeInsets

  • EdgeInsets.all() 各个方向使用同一组值
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          color: Colors.lightBlue,
          margin: const EdgeInsets.all(100.0),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • EdgeInsets.only() 可指定方向和值

leftrighttopbottom 四个方向的值

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          color: Colors.lightBlue,
          margin: const EdgeInsets.only(left: 100.0),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • margin 外边距
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          color: Colors.lightBlue,
          margin: const EdgeInsets.only(top: 100.0),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • padding 内边距
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          color: Colors.lightBlue,
          padding: const EdgeInsets.all(70.0),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

从结果可以看出来,里面的内容已经被挤的有些部分看不到了

image.png


decoration 装饰器

  • color 这个颜色和外层的颜色是二选一的,如果装饰器里面设置了颜色,外面就不能设置
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          alignment: Alignment.topCenter,
          margin: const EdgeInsets.only(top: 40.0),
          decoration: const BoxDecoration(color: Colors.red),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • border 边框

可以给某个方向添加边框,添加边框的颜色,粗细

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          alignment: Alignment.topCenter,
          margin: const EdgeInsets.all(100.0),
          decoration: const BoxDecoration(
              border: Border(
                  top: BorderSide.none,
                  bottom: BorderSide(color: Colors.pink, width: 10.0),
                  left: BorderSide(color: Colors.green),
                  right: BorderSide(color: Colors.yellow))),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • gradient 填充框时使用的渐变
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          margin: const EdgeInsets.all(40.0),
          decoration: const BoxDecoration(
            gradient: LinearGradient(
                colors: [Colors.lightBlue, Colors.pink, Colors.yellow]),
          ),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • borderRadius 边缘圆角
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          margin: const EdgeInsets.all(40.0),
          decoration: const BoxDecoration(
              color: Colors.blue,
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(8),
                topRight: Radius.circular(8),
              )),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png

---
  • image 添加背景图片
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          margin: const EdgeInsets.all(40.0),
          decoration: const BoxDecoration(
            image: DecorationImage(
              image: AssetImage(
                'assets/images/icon.png',
              ),
              fit: BoxFit.contain,
            ),
          ),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


  • boxShadow 阴影
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          width: 200.0,
          height: 200.0,
          margin: const EdgeInsets.all(40.0),
          decoration: BoxDecoration(
            boxShadow: [
              BoxShadow(
                color: const Color.fromARGB(255, 203, 52, 52).withOpacity(0.15),
                offset: const Offset(0, 1),
                spreadRadius: 0,
                blurRadius: 4,
              )
            ],
          ),
          child: const Text(
            'hellow world',
            style: TextStyle(
              fontSize: 20.0,
            ),
          )),
    );
  }
}

image.png


SizedBox 有固定宽高的盒子容器

是上面Container 的简单版本

  • width
  • height
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
      margin: const EdgeInsets.only(top: 100.0),
      child: const SizedBox(
        width: 100.0,
        height: 100.0,
        child: Text('我是内容,我是内容,我是内容,我是内容,我是内容,我是内容'),
      ),
    ));
  }
}

image.png


GestureDetector 手势识别

可以识别点击、双击、长按事件、拖动、缩放等手势。

onTap 点击事件

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: GestureDetector(
      onTapDown: (TapDownDetails tapDownDetails) {
        print('按下时');
      },
      onTapUp: (TapUpDetails tapUpDetails) {
        print('抬起时');
      },
      onTap: () {
        print('点击时');
      },
      onTapCancel: () {
        print('点击取消');
      },
      child: Center(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
        ),
      ),
    ));
  }
}

点击时的事件触发的先后顺序为:按下时 -> 抬起时 -> 点击时

image.png

点击拖动时的事件触发的先后顺序为:按下时 -> 点击取消 image.png


onDoubleTap 双击事件

  onDoubleTap: () {
        print('双击');
 },

image.png


onLongPress 长按事件

  onLongPressStart: (v) {
        print('开始长按');
      },
  onLongPressMoveUpdate: (v) {
    print('长按移动');
  },
  onLongPressUp: () {
    print('长按抬起');
  },
  onLongPressEnd: (v) {
    print('长按结束');
  },
  onLongPress: () {
    print('长按');
  },

长按时的事件触发的先后顺序为:按下时 ->点击取消 -> 开始长按 -> 长按 -> 长按结束 -> 长按抬起

image.png

长按后移动的事件触发的先后顺序为:按下时 -> 点击取消 -> 开始长按 -> 长按 -> 长按移动 -> 长按结束 -> 长按抬起

image.png


onScale 缩放事件

  onScaleStart: (v) {
    print('开始缩放');
   },
  onScaleUpdate: (v) {
    print('缩放更新');
  },
  onScaleEnd: (v) {
    print('开始缩放');
  },

缩放的事件触发的先后顺序为:**按下时 -> 点击取消 -> 开始缩放 -> 缩放更新 -> 结束缩放 **

image.png


Column 列表

children 接收的是一个数组

import 'package:flutter/material.dart';

class APage extends StatelessWidget {
  const APage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('A页面')),
      body: Center(
          child: Column(children: [
        ElevatedButton(
            onPressed: () {
              print('1');
            },
            child: const Text('按钮1')),
        ElevatedButton(
            onPressed: () {
              print('2');
            },
            child: const Text('按钮2')),
      ])),
    );
  }
}

image.png

Center 居中布局

常用于我们需要居中的样式

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(child: Text('我是内容')),
    );
  }
}

image.png


Row 水平布局

接收一个数组,可平铺多个widget

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: Row(
      children: <Widget>[
        Container(
          height: 50,
          width: 100,
          color: Colors.red,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.green,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.blue,
        ),
      ],
    )));
  }
}

image.png


mainAxisAlignment 对齐方式

  • start
import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: Row(
      mainAxisAlignment: MainAxisAlignment.start,
      children: <Widget>[
        Container(
          height: 50,
          width: 100,
          color: Colors.red,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.green,
        ),
        Container(
          height: 50,
          width: 100,
          color: Colors.blue,
        ),
      ],
    )));
  }
}

image.png

  • center 居中
  mainAxisAlignment: MainAxisAlignment.center,

image.png


  • end 以结束位置对齐
 mainAxisAlignment: MainAxisAlignment.end,

image.png


  • spaceAround 分散对齐
  mainAxisAlignment: MainAxisAlignment.spaceAround,

image.png


  • spaceBetween
 mainAxisAlignment: MainAxisAlignment.spaceBetween,

image.png


-spaceEvenly

 mainAxisAlignment: MainAxisAlignment.spaceEvenly,

image.png


spaceAroundspaceEvenly区别是:

  • spaceAround:第一个子控件距开始位置和最后一个子控件距结尾位置是其他子控件间距的一半。

  • spaceEvenly:所有间距一样。


crossAxisAlignment

  • start
 crossAxisAlignment: CrossAxisAlignment.start,

image.png


  • center
 crossAxisAlignment: CrossAxisAlignment.center,

image.png


  • end
 crossAxisAlignment: CrossAxisAlignment.end,

image.png


  • stretch
 crossAxisAlignment: CrossAxisAlignment.stretch,

image.png


textDirection 排列方向

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Row(
      textDirection: TextDirection.rtl,
      children: <Widget>[
        Container(
          height: 50,
          width: 100,
          color: Colors.red,
        ),
        Container(
          height: 100,
          width: 100,
          color: Colors.green,
        ),
        Container(
          height: 150,
          width: 100,
          color: Colors.blue,
        ),
      ],
    ));
  }
}

image.png


mainAxisSize

主轴尺寸由mainAxisSize属性控制,仅有minmax两种方式,默认是max方法。min表示尽可能小,而max表示尽可能大

import 'package:flutter/material.dart';

class Index extends StatelessWidget {
  const Index({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
      margin: const EdgeInsets.only(top: 100),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Container(
            height: 50,
            width: 100,
            color: Colors.red,
          ),
          Container(
            height: 50,
            width: 100,
            color: Colors.green,
          ),
          Container(
            height: 50,
            width: 100,
            color: Colors.blue,
          ),
        ],
      ),
    ));
  }
}

image.png

路由配置

新建3个同级页面,来回跳转

Navigator.push 即可跳转到指定页面

Navigator.pop 则会回退一页

APage:

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

class APage extends StatelessWidget {
  const APage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('A页面')),
      body: Center(
          child: Column(children: [
        ElevatedButton(
            onPressed: () {
              Navigator.push(context, MaterialPageRoute(builder: (context) {
                return const BPage();
              }));
            },
            child: const Text('go Bpage')),
        ElevatedButton(
            onPressed: () {
              Navigator.pop(context);
            },
            child: const Text('go back')),
      ])),
    );
  }
}


A 页面展示:

image.png

BPage:

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

class BPage extends StatelessWidget {
  const BPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('B页面')),
      body: Center(
          child: ElevatedButton(
        child: const Text(
          'go Cpage',
        ),
        onPressed: () {
          Navigator.push(context, MaterialPageRoute(builder: (context) {
            return const CPage();
          }));
        },
      )),
    );
  }
}


B 页面展示:

image.png

CPage:

import 'package:flutter/material.dart';

class CPage extends StatelessWidget {
  const CPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('C页面')),
      body: Center(
          child: ElevatedButton(
        child: const Text(
          'go back',
        ),
        onPressed: () {
          Navigator.pop(context);
        },
      )),
    );
  }
}

C 页面展示:

image.png

路由传参数

首先组件需要是StatefulWidget有状态组件

现在我们模拟从A页面跳转到B页面,在跳转过程中传参数,在B页面收到A的参数

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

class APage extends StatefulWidget {
  const APage({Key? key}) : super(key: key);
  @override
  State<APage> createState() => APageContent();
}

class APageContent extends State<APage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('A页面')),
      body: Center(
          child: Column(children: [
        ElevatedButton(
            onPressed: () {
              Navigator.push(context, MaterialPageRoute(builder: (context) {
                return BPage(
                  name: '哈哈哈哈',
                );
              }));
            },
            child: const Text('跳转到B页面,并携带参数name')),
    );
  }
}


截屏2022-06-11 19.25.22.png

B页面

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

class BPage extends StatefulWidget {
  String name;
  BPage({Key? key, required this.name}) : super(key: key);
  @override
  State<BPage> createState() => BPageContent();
}

class BPageContent extends State<BPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('B页面')),
      body: Center(
          child: ElevatedButton(
        child: Text(
          '参数值 ${widget.name}',
        ),
        onPressed: () {
          print('参数值${widget.name}');
        },
      )),
    );
  }
}


截屏2022-06-11 19.25.33.png

那我们B跳转回A页面时如何给A页面回参呢?

A 页面:

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

class APage extends StatefulWidget {
  const APage({Key? key}) : super(key: key);
  @override
  State<APage> createState() => APageContent();
}

class APageContent extends State<APage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('A页面')),
      body: Center(
          child: Column(children: [
        ElevatedButton(
            onPressed: () {
            // 在这里定义返回结果
              var result =
                  Navigator.push(context, MaterialPageRoute(builder: (context) {
                return BPage(
                  name: '哈哈哈哈',
                );
              }));
              result.then((value) => print(('$value')));
            },
            child: const Text('跳转到B页面,并携带参数name')),
      ])),
    );
  }
}

B页面:

import 'package:flutter/material.dart';

class BPage extends StatefulWidget {
  String name;
  BPage({Key? key, required this.name}) : super(key: key);
  @override
  State<BPage> createState() => BPageContent();
}

class BPageContent extends State<BPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('B页面')),
      body: Center(
          child: ElevatedButton(
        child: Text(
          '参数值 ${widget.name}',
        ),
        onPressed: () {
          Navigator.pop(context, '清凉');
        },
      )),
    );
  }
}

image.png

命名路由

我们每次使用Navigator跳转要传一大堆参数,还要修改类的结构,我们有没有方法把路由的内容抽出来?那是当然有

根文件:

import 'package:flutter/material.dart';
import './src/pages/connect/login_view.dart';
import 'package:im_flutter_demo/src/pages/home/home_view.dart';
import 'src/pages/connect/A_page.dart';


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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // root
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'App名称',
      debugShowCheckedModeBanner: false,
      home: const LoginPages(),
      routes: {
        '/A': (context) => const APage(),
        '/home': (context) => const HomePage(),
      },
    );
  }
}

A页面:

import 'package:flutter/material.dart';
import '../home/home_view.dart';
import './A_page.dart';


class LoginPages extends StatefulWidget {
  const LoginPages({Key? key}) : super(key: key);

  @override
  State<LoginPages> createState() => LoginContent();
}

class LoginContent extends State<LoginPages> {
  String _result = '';
  Future<void> _incrementCounter()  {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'loginpage',
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: Container(
            child: Column(children: <Widget>[
              ElevatedButton.icon(
                  onPressed: () {
                  // 此处直接用 Navigator.pushNamed ,后面第二个参数就是跳转的路由地址,即可完成跳转
                    Navigator.pushNamed(context, '/home');
                  },
                  icon: const Icon(Icons.home),
                  label: const Text('home')),
              ElevatedButton.icon(
                  onPressed: () {
                    Navigator.pushNamed(context, '/A');
                  },
                  icon: const Icon(Icons.backpack),
                  label: const Text('A')),
            ]),
            alignment: Alignment.topCenter,
            margin: const EdgeInsets.all(100.0),
          ),
        ),
      ),
    );
  }
}

注:这个routes的位置要位于MaterialApp 这个根文件,我试过放在LoginPage 会报错

 // 如果需要传参,可通过第三个参数 :arguments 来传输
 
 Navigator.pushNamed(context, '/home', arguments: 'aaa');

路由钩子,特殊匹配

import 'package:flutter/material.dart';

import './src/pages/connect/login_view.dart';
import 'package:im_flutter_demo/src/pages/home/home_view.dart';
import 'src/pages/connect/A_page.dart';
import 'package:im_flutter_demo/src/pages/connect/C_page.dart';


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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // root
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'App名称',
      debugShowCheckedModeBanner: false,
      
      // 根页面地址
      home: const LoginPages(),
      
      // 路由和对应的页面
      routes: {
        '/A': (context) => const APage(),
        '/home': (context) => const HomePage(),
        '/login': (context) => const LoginPages(),
      },
      
      // 初始化路由位置
      initialRoute: '/',
      
      // 钩子中的拦截判断
      onGenerateRoute: (RouteSettings settings) {
        if (settings.name == '/z') {
          return MaterialPageRoute(builder: (context) => const HomePage());
        }
        return null;
      },
      
      // 找不到路由
      onUnknownRoute: (RouteSettings settings) {
        return MaterialPageRoute(builder: (context) => const CPage());
      },
    );
  }
}

MaterialApp路由匹配规则:

  • 路由为'/'时,home不为 null则使用 home
  • 使用routes指定的路由
  • 使用onGenerateRoute 生成的路由,处理除 homeroutes 以外的路由
  • 如果上面都不匹配则调用 onUnknownRoute

参考文献:《Flutter实战·第二版》

文章写到这里还没有结束,我会继续更新,如果正在看文章的你有任何疑惑点🤔,欢迎评论区留言。

1636002554133.jpg

1636002503362.jpg


如果亲感觉我的文章还不错的话,可以一下添加关注哦!

内容还在持续更新中,怕错过更新的点个关注再走呗!点个关注不迷路哦!😄

求内推

注:如果有小伙伴公司正在招聘,可联系我哦,不胜感激!技术栈:react,ts,flutter,antd,webpack...,可以参考我的文章。地点:北京