跳到主要内容

Flutter Widget

Text 组件

Text 用于显示简单样式文本,它包含一些控制文本显示样式的一些属性

  • textAlign:文本的对齐方式,可以选择左对齐、右对齐还是居中
对齐的参考系是 Text widget 本身

虽然指定了居中对齐,但因为 Text 文本内容宽度不足一行, Text 的宽度和文本内容长度相等,那么这时指定对齐方式是没有意义的, 只有 Text 宽度大于文本内容长度时指定此属性才有意义

  • maxLines 指定文本显示的最大行数,默认情况下,文本是自动折行的,如果指定此参数,则文本最多不会超过指定的行
  • overflow 如果有多余的文本,可以通过 overflow 来指定截断方式,默认是直接截断,指定的截断方式 TextOverflow.ellipsis,它会将多余文本截断后以省略符“...”表示

TextStyle

TextStyle 用于指定文本显示的样式如颜色、字体、粗细、背景等

Text("TextStyle 用于指定文本显示的样式",
style: TextStyle(
color: Colors.blue,
fontSize: 18.0,
height: 1.2,
fontFamily: "Courier",
background: Colors.yellow,
decoration:TextDecoration.underline,
decorationStyle: TextDecorationStyle.dashed
),
);

TextSpan

Text 的所有文本内容只能按同一种样式,如果需要对一个 Text 内容的不同部分按照不同的样式显示, 就可以使用 TextSpan,它代表文本的一个 “片段”

DefaultTextStyle

在 Widget 树中,文本的样式默认是可以被继承的(子类文本类组件未指定具体样式时可以使用 Widget 树中父级设置的默认样式), 因此,如果在 Widget 树的某一个节点处设置一个默认的文本样式,那么该节点的子树中所有文本都会默认使用这个样式, 而 DefaultTextStyle 正是用于设置默认文本样式

import "package:flutter/material.dart";

class MyText extends StatelessWidget {
const MyText({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Text 组件',
),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
// backgroundColor: Colors.pinkAccent,
body: const Padding(
padding: EdgeInsets.all(15),
child: DefaultTextStyle(
style: TextStyle(
fontSize: 16,
color: Colors.orange,
),
child: Column(
textDirection: TextDirection.ltr,
children: [
Text(
'Text 组件,用于显示简单样式文本,包含一些控制文本显示样式的一些属性',
textAlign: TextAlign.left,
textDirection: TextDirection.rtl,
textScaler: TextScaler.linear(1.2),
style: TextStyle(
color: Colors.white,
fontSize: 18,
height: 1.5,
fontFamily: 'Courier',
),
),
Text(
"Text 组件,用于显示简单样式文本Text 组件,用于显示简单样式文本Text 组件,用于显示简单样式文本",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text.rich(
TextSpan(
children: [
TextSpan(text: 'TextSpan 组件'),
TextSpan(
text: '相关链接:"https://flutterchina.club"',
style: TextStyle(color: Colors.blue),
),
],
),
),
],
),
),
),
);
}
}

字体使用

在 Flutter 中使用字体分两步完成:

  • 在 pubspec.yaml 中声明字体资源,以确会打包到应用程序中
  • 通过 TextStyle fontFamily 属性使用字体
# pubspec.yaml
# 字体存放目录:assets/fonts/
flutter:
uses-material-design: true
# 图片静态资源
assets:
- assets/images/

# 字体资源
fonts:
# 阿里妈妈刀隶体
- family: AlimamaDaoLiTi
fonts:
- asset: assets/fonts/AlimamaDaoLiTi/AlimamaDaoLiTi.ttf

# 阿里妈妈数黑体
- family: AlimamaShuHeiTiBold
fonts:
- asset: assets/fonts/AlimamaShuHeiTiBold/AlimamaShuHeiTiBold.ttf
Text(
'阿里妈妈刀隶体',
style: TextStyle(
fontFamily: 'AlimamaDaoLiTi',
fontSize: 30,
),
),
Text(
'阿里妈妈刀隶体,外露锋芒,耀其精神,介于隶楷之间,保持着浓重的隶书方笔意味,给人以坚实、朴茂、稚拙、倔犟之感,打破常规常态的匀称均衡',
style: TextStyle(
fontFamily: 'AlimamaDaoLiTi',
fontSize: 16,
height: 1.5,
),
),
Text(
'阿里妈妈数黑体',
style: TextStyle(
fontSize: 30,
fontFamily: 'AlimamaShuHeiTiBold',
),
),
Text(
'阿里妈妈·智造字自产自研打造了第一款AI字体产品——阿里妈妈数黑体正式上线。这款字的生成是人机协同工作的成果,设计原型,智能参与,人工干预,人机循环优化,直到最终生成满意标准字库',
style: TextStyle(
fontFamily: 'AlimamaShuHeiTiBold',
height: 1.5,
fontSize: 16,
),
),

Button 组件

Material 组件库中提供了多种按钮组件如 ElevatedButton、TextButton、OutlinedButton 等, 它们都是直接或间接对 RawMaterialButton 组件的包装定制,所以他们大多数属性都和 RawMaterialButton 一样

Material 库中的按钮都有如下相同点
  • 按下时都会有 “水波动画”(又称 “涟漪动画”,就是点击时按钮上会出现水波扩散的动画)
  • 有一个 onPressed 属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击

ElevatedButton

ElevatedButton 即"漂浮"按钮,它默认带有阴影和灰色背景

TextButton

TextButton 即文本按钮,默认背景透明并不带阴影

OutlinedButton

OutlinedButton 默认有一个边框,不带阴影且背景透明。按下后,边框颜色会变亮、同时出现背景和阴影(较弱)

IconButton

IconButton 是一个可点击的 Icon,不包括文字,默认没有背景,点击后会出现背景

带图标的按钮

ElevatedButton、TextButton、OutlinedButton 都有一个 icon 构造函数,通过它可以轻松创建带图标的按钮

import "package:flutter/material.dart";

class MyButton extends StatelessWidget {
const MyButton({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Button 组件学习'),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
body: Padding(
padding: const EdgeInsets.all(15),
child: DefaultTextStyle(
style: const TextStyle(
fontSize: 16,
color: Colors.orange,
),
child: Column(
children: [
const Text(
'Button 组件练习',
style: TextStyle(fontSize: 24),
),
const Text('ElevatedButton 即"漂浮"按钮,它默认带有阴影和灰色背景。按下后,阴影会变大'),
ElevatedButton(
child: const Text('ElevatedButton 按钮'),
onPressed: () => {},
),
ElevatedButton.icon(
icon: const Icon(Icons.send),
label: const Text("发送"),
onPressed: () => {},
),
const Text('TextButton 即文本按钮,默认背景透明并不带阴影。按下后,会有背景色'),
TextButton(
child: const Text('TextButton 按钮'),
onPressed: () => {},
),
TextButton.icon(
icon: const Icon(Icons.info),
label: const Text("我是文本按钮"),
onPressed: () => {},
),
const Text(
'OutlinedButton 默认有一个边框,不带阴影且背景透明。按下后,边框颜色会变亮、同时出现背景和阴影(较弱)'),
OutlinedButton(
child: const Text('OutlinedButton 按钮'),
onPressed: () => {},
),
OutlinedButton.icon(
icon: const Icon(Icons.add),
label: const Text("添加"),
onPressed: () => {},
),
const Text('IconButton 是一个可点击的Icon,不包括文字,默认没有背景,点击后会出现背景'),
IconButton(
icon: const Icon(Icons.local_activity),
onPressed: () => {},
),
],
),
),
),
);
}
}

图片

在 flutter 中可以通过 Image 组件 来加载并显示图片, Image 的数据源可以是 asset、文件、内存以及网络

ImageProvider

ImageProvider 是一个抽象类,主要定义了图片数据获取的接口 load(),从不同的数据源获取图片需要实现不同的 ImageProvider

  • AssetImage 实现了从 Asset 中加载图片的 ImageProvider
  • NetworkImage 实现了从网络加载图片的 ImageProvider

Image

Image 组件有一个必选的 image 参数,它对应一个 ImageProvider, 在显示图片时定义了一系列参数,通过这些参数可以控制图片的显示外观、大小、混合效果等, Flutter 框架对加载过的图片是有缓存的(内存)

Image 部分参数
  • image: Image.asserts('assets/images/avatar.png') 必选参数
  • width: 100.0 设置图片的宽,当不指定宽高时,图片会根据当前父容器的限制,尽可能的显示其原始大小,如果只设置 width、height 的其中一个,那么另一个属性默认会按比例缩放
  • height: 100.0 设置图片高度
  • color: Colors.blue 图片的混合色值,在图片绘制时可以对每一个像素进行颜色混合处理,color 指定混合色,而 colorBlendMode 指定混合模式
  • colorBlendMode: BlendMode.difference 在图片绘制时可以对每一个像素进行颜色混合处理,color 指定混合色,而 colorBlendMode 指定混合模式
  • fit: BoxFit.cover 用于在图片的显示空间和图片本身大小不同时指定图片的适应模式
    • 适应模式是在 BoxFit 中定义,它是一个枚举类型
      • BoxFit.fill 会拉伸填充满显示空间,图片本身长宽比会发生变化,图片会变形
      • BoxFit.cover 会按图片的长宽比放大后居中填满显示空间,图片不会变形,超出显示空间部分会被剪裁
      • BoxFit.contain 图片的默认适应规则,图片会在保证图片本身长宽比不变的情况下缩放以适应当前显示空间,图片不会变形
      • BoxFit.fitWidth 图片的宽度会缩放到显示空间的宽度,高度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁
      • BoxFit.fitHeight 图片的高度会缩放到显示空间的高度,宽度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁
      • BoxFit.none 图片没有适应策略,会在显示空间内显示图片,如果图片比显示空间大,则显示空间只会显示图片中间部分
  • alignment: Alignment.center 对齐方式
  • repeat: ImageRepeat.noRepeat 重复方式,当图片本身大小小于显示空间时,指定图片的重复规则

从 asset 中加载图片

1、在项目根目录下创建 /assets/images 目录,将项目使用的图片放到该目录

2、在项目根目录 pubspec.yaml 文件,flutter 属性中 申明 资源的路径

name: flutter_app1
description: 'flutter 学习项目'
publish_to: 'none'
version: 0.1.0

environment:
sdk: '>=3.2.5 <4.0.0'

dependencies:
flutter:
sdk: flutter
card_swiper: ^3.0.1

dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0

flutter:
uses-material-design: true

# 图片静态资源
assets:
- assets/images/

# 字体资源
fonts:
# iconfont
- family: Iconfont
fonts:
- asset: assets/iconfont/iconfont.ttf

# 阿里妈妈刀隶体
- family: AlimamaDaoLiTi
fonts:
- asset: assets/fonts/AlimamaDaoLiTi/AlimamaDaoLiTi.ttf

# 阿里妈妈数黑体
- family: AlimamaShuHeiTiBold
fonts:
- asset: assets/fonts/AlimamaShuHeiTiBold/AlimamaShuHeiTiBold.ttf
yaml 文件对缩进严格

yaml 文件对缩进严格,所以必须严格按照每一层两个空格的方式进行缩进,assets 前面应有两个空格

加载图片

提示
  • Image.asset 加载项目中图片资源
  • Image.network 加载网络图片资源
  • Image.file 加载本地图片,拍照时图片预览等

加载 asset 图片

// 两种方式 都可以
Image(
image: AssetImage('assets/images/avatar.png'),
width: 100.0,
height: 100.0,
fit: BoxFit.contain,
aligment: Aligment.center,
repeat: ImageRepet.noRepeat
),
Image.asset(
'assets/images/avatar.png',
width: 100.0,
height: 100.0,
fit: BoxFit.contain,
fit: BoxFit.contain,
aligment: Aligment.center,
repeat: ImageRepet.noRepeat
),

加载 网络图片

// 两种方式 都可以
Image(
image: NetworkImage(
'https://storage.googleapis.com/cms-storage-bucket/images/Cupid_Dash_BlueBG.width-635.png',
),
width: 100.0,
height: 100.0,
),
Image.network(
'https://storage.googleapis.com/cms-storage-bucket/images/Cupid_Dash_BlueBG.width-635.png',
width: 100.0,
height: 100.0,
),

icon 字体图标

Flutter 中,可以像 Web 开发一样使用 iconfont,iconfont 即 “字体图标”, 它是将图标做成字体文件,然后通过指定不同的字符而显示不同的图片, 在字体文件中,每一个字符都对应一个位码,而每一个位码对应一个显示字形,不同的字体就是指字形不同,即字符对应的字形是不同的。 而在 iconfont 中,只是将位码对应的字形做成了图标,所以不同的字符最终就会渲染成不同的图标

字体图标和图片相比优势
  • 体积小:可以减小安装包大小
  • 矢量的:iconfont 都是矢量图标,放大不会影响其清晰度
  • 可以应用文本样式:可以像文本一样改变字体图标的颜色、大小对齐等
  • 可以通过 TextSpan 和文本混用

使用 Material Design 字体图标

Flutter 默认包含了一套 Material Design 的字体图标,在 pubspec.yaml 文件中的配置如下

# pubspec.yaml
flutter:
uses-material-design: true
// 字体 fontFamily 为:MaterialIcons
String icons = '\ue87e \uE03e \uE237 \uE287 \uE87d \ue994';
Text(
icons,
style: TextStyle(
fontFamily: 'MaterialIcons',
fontSize: 24.0,
color: Colors.orange,
),
),

上面方式需要提供每个图标的码点,对开发者并不友好, Flutter 封装了 IconData 和 Icon 来专门显示字体图标, Icons 类中包含了所有 Material Design 图标的 IconData 静态变量定义

Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.accessible,
size: 32.0,
color: Colors.redAccent,
),
Icon(
Icons.error,
size: 32.0,
color: Colors.blueAccent,
),
Icon(
Icons.favorite,
size: 32.0,
color: Colors.orange,
),
],
),

使用自定义字体图标

在阿里巴巴矢量图标库网站中:资源管理 -> 我的项目,创建一个自己的项目如,flutter_app1 ,将所需要的图标都加入该项目中

添加完所需图标后,使用 Unicode 方式,并点击 下载至本地,在 Flutter 中使用 ttf 格式即可

下载字体包

在 pubspec.yaml 文件添加 字体包源

# pubspec.yaml
flutter:
uses-material-design: true

# 图片静态资源
assets:
- assets/images/

# 字体资源
fonts:
# iconfont
- family: Iconfont
fonts:
- asset: assets/iconfont/iconfont.ttf

使用 阿里巴巴矢量图标库

1、通过 Text 组件使用,Text 组件第一个参数为:\u 加上 unicode,Iconfont 给出的是 &#x e622;,将 &#x 前缀去掉

String icons = '\ue614 \ue74c \ue896 \ue617';
Text(
'\ue622',
style: TextStyle(
fontFamily: 'Iconfont',
fontSize: 32.0,
color: Colors.green,
),
),
Text(
icons,
style: TextStyle(
fontFamily: 'Iconfont',
fontSize: 32.0,
color: Colors.green,
),
),

2、通过 Icon + IconData 使用,IconData 的第一个参数 为 codePoint,0x + unicode 码 0x 表示是十六进制,Iconfont 给出的是 &#x e622;,将 &#x 前缀去掉

IconData 类的参数
IconData IconData(
int codePoint, {
String? fontFamily,
String? fontPackage,
bool matchTextDirection = false,
List<String>? fontFamilyFallback,
})
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
IconData(
0xe622,
fontFamily: 'Iconfont',
matchTextDirection: true,
),
color: Colors.pinkAccent,
size: 32.0,
),
Icon(
IconData(
0xe896,
fontFamily: 'Iconfont',
matchTextDirection: true,
),
color: Colors.pinkAccent,
size: 32.0,
),
],
),

封装一个 MyIcons 类

// 目录:/lib/components/my_icons.dart

import 'package:flutter/widgets.dart';

class MyIcons {
static IconData erweima = const IconData(
0xe614,
fontFamily: 'Iconfont',
matchTextDirection: true,
);
static IconData open = const IconData(
0xe74c,
fontFamily: 'Iconfont',
matchTextDirection: true,
);
}

在其他页面使用 MyIcons

// 当前页面:my_icon_page.dart

import 'package:flutter_app1/components/my_icons.dart';

Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
MyIcons.erweima,
color: Colors.pinkAccent,
size: 32.0,
),
Icon(
MyIcons.open,
color: Colors.pinkAccent,
size: 32.0,
),
],
),

这样需要将每一个图片手动添加到 MyIcons 中,下面介绍如何在 阿里巴巴矢量图标库 页面