一、文本

Text

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

  1. Text("Hello world ! " * 4,
  2. textAlign: TextAlign.center,
  3. textScaleFactor: 1.5, // 文本相对于当前字体大小的缩放因子
  4. maxLines: 1,
  5. overflow: TextOverflow.ellipsis,
  6. );

文本样式:

  1. Text("Hello world",
  2. style: TextStyle(
  3. color: Colors.blue,
  4. fontSize: 18.0,
  5. height: 1.2, // 行高
  6. fontFamily: "Courier",
  7. background: new Paint()..color=Colors.yellow,
  8. decoration: TextDecoration.underline,
  9. decorationStyle: TextDecorationStyle.dashed
  10. ),
  11. );

TextStyle

文字样式可以使用 TextStyle 定义

TextDecoration

TextDecoration: 文字装饰

  • TextDecoration.none 默认
  • TextDecoration.overline
  • TextDecoration.lineThrough
  • TextDecoration.underline
  • TextDecoration.combine(List<TextDecoration>) 组合多个装饰

TextDecoration.combine 可以组合多种文字装饰, 比如:

  1. TextDecoration.combine([TextDecoration.overline, TextDecoration.underline])

TextDecorationStyle

TextDecorationStyle: 文字装饰样式

  • TextDecorationStyle.solid
  • TextDecorationStyle.dashed
  • TextDecorationStyle.dotted
  • TextDecorationStyle.double
  • TextDecorationStyle.wavy

TextSpan

TextSpan 文字片段

定义:

  1. const TextSpan({
  2. TextStyle style,
  3. Sting text,
  4. List<TextSpan> children,
  5. GestureRecognizer recognizer,
  6. });

示例:

  1. Text.rich(TextSpan(
  2. children: [
  3. TextSpan(
  4. text: "Home: "
  5. ),
  6. TextSpan(
  7. text: "flutterchina.club",
  8. style: TextStyle(
  9. color: Colors.blue
  10. ),
  11. recognizer: _tapRecognizer
  12. ),
  13. ]
  14. ))

默认样式的继承

使用 DefaultTextStyle 设置默认样式, 子Widget可以继承默认样式, 除非设置 inherit: false

  1. DefaultTextStyle(
  2. // 1.设置文本默认样式
  3. style: TextStyle(
  4. color:Colors.red,
  5. fontSize: 20.0,
  6. ),
  7. textAlign: TextAlign.start,
  8. child: Column(
  9. crossAxisAlignment: CrossAxisAlignment.start,
  10. children: <Widget>[
  11. Text("hello world"), // 继承默认样式
  12. Text("I am Jack"), // 继承默认样式
  13. Text("I am Jack",
  14. style: TextStyle(
  15. inherit: false, // 2.不继承默认样式
  16. color: Colors.grey
  17. ),
  18. ),
  19. ],
  20. ),
  21. );

自定义字体

要使用自定义字体, 需要在pubspec.yaml中先进行声明:

  1. flutter:
  2. fonts:
  3. - family: Raleway
  4. fonts:
  5. - asset: assets/fonts/Raleway-Regular.ttf
  6. - asset: assets/fonts/Raleway-Medium.ttf
  7. weight: 500
  8. - asset: assets/fonts/Raleway-SemiBold.ttf
  9. weight: 600
  10. - family: AbrilFatface
  11. fonts:
  12. - asset: assets/fonts/abrilfatface/AbrilFatface-Regular.ttf

在Widget中使用:

  1. Text(
  2. "Use the font for this text",
  3. style: TextStyle(
  4. fontFamily: 'Raleway',
  5. ),
  6. );

富文本

RichText 可以容纳富文本内容:

  1. RichText(
  2. text: TextSpan(
  3. text: 'Hello ',
  4. style: DefaultTextStyle.of(context).style,
  5. children: <TextSpan>[
  6. TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
  7. TextSpan(text: ' world!'),
  8. ],
  9. ),
  10. )

使用 Text.rich 可以实现相同的功能

二、按钮

漂浮形态的按钮

RaisedButton 创建一个凸起的材质矩形按钮 (Material Design风格)

  1. RaisedButton(
  2. child: Text("normal"),
  3. onPressed: () {},
  4. );

自定义按钮样式:

  1. RaisedButton(
  2. color: Colors.blue,
  3. highlightColor: Colors.blue[700], // 按钮按下时的背景颜色
  4. colorBrightness: Brightness.dark, // 按钮主题
  5. splashColor: Colors.grey, // 点击时,水波动画中水波的颜色
  6. child: Text("Submit"),
  7. shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
  8. onPressed: () {},
  9. );

扁平形态的按钮

FlatButton 创建一个扁平化的按钮

  1. FlatButton(
  2. child: Text("normal"),
  3. onPressed: () {},
  4. );

FlatButton的定义

  1. const FlatButton({
  2. ...
  3. @required this.onPressed, // 按钮点击回调
  4. @required this.child, // 按钮的内容
  5. this.textColor, // 按钮文字颜色
  6. this.highlightColor, // 按钮按下时的背景颜色
  7. this.splashColor, // 点击时,水波动画中水波的颜色
  8. this.colorBrightness, // 按钮主题,默认是浅色主题
  9. this.enabled, // 是否可用
  10. this.disabledTextColor, // 按钮禁用时的文字颜色
  11. this.disabledColor, // 按钮禁用时的背景颜色
  12. this.color, // 按钮背景颜色
  13. this.padding, // 按钮的填充
  14. this.shape, // 外形
  15. })

自定义按钮样式:

  1. FlatButton(
  2. color: Colors.blue,
  3. highlightColor: Colors.blue[700],
  4. colorBrightness: Brightness.dark,
  5. splashColor: Colors.grey,
  6. child: Text("Submit"),
  7. shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
  8. onPressed: () {},
  9. );

带边框的按钮

OutlineButton 创建一个带边框的按钮

  1. OutlineButton(
  2. child: Text("normal"),
  3. onPressed: () {},
  4. )

带图标的按钮

  1. IconButton(
  2. icon: Icon(Icons.thumb_up),
  3. onPressed: () {},
  4. )
  5. RaisedButton.icon(
  6. icon: Icon(Icons.send),
  7. label: Text("发送"),
  8. onPressed: () {},
  9. );
  10. FlatButton.icon(
  11. icon: Icon(Icons.info),
  12. label: Text("详情"),
  13. onPressed: () {},
  14. );
  15. OutlineButton.icon(
  16. icon: Icon(Icons.add),
  17. label: Text("添加"),
  18. onPressed: () {},
  19. );

下拉选择按钮

DropdownButton: 下拉选择按钮,示例:
003.gif

  1. String dropdownValue = 'One';
  2. @override
  3. Widget build(BuildContext context) {
  4. return Scaffold(
  5. body: Center(
  6. child: DropdownButton<String>(
  7. value: dropdownValue,
  8. onChanged: (String newValue) {
  9. setState(() {
  10. dropdownValue = newValue;
  11. });
  12. },
  13. items: <String>['One', 'Two', 'Free', 'Four']
  14. .map<DropdownMenuItem<String>>((String value) {
  15. return DropdownMenuItem<String>(
  16. value: value,
  17. child: Text(value),
  18. );
  19. })
  20. .toList(),
  21. ),
  22. ),
  23. );
  24. }

弹出选择按钮

PopupMenuButton: 弹出选择按钮,示例:
008.gif

  1. class HomePage extends StatefulWidget {
  2. @override
  3. createState() => new _HomePageState();
  4. }
  5. class _HomePageState extends State<HomePage> {
  6. @override
  7. Widget build(BuildContext context) {
  8. return Scaffold(
  9. appBar: new AppBar(
  10. title: Text('首页'),
  11. actions: [
  12. PopupMenuButton<String>(
  13. icon: Icon(Icons.more_horiz),
  14. offset: Offset(100, 100),
  15. itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
  16. const PopupMenuItem<String>(
  17. value: "1",
  18. child: ListTile(
  19. leading: Icon(Icons.share),
  20. title: Text('分享'),
  21. ),
  22. ),
  23. PopupMenuDivider(),//分割线
  24. const PopupMenuItem<String>(
  25. value: "2",
  26. child: ListTile(
  27. leading: Icon(Icons.settings),
  28. title: Text('设置'),
  29. ),
  30. ),
  31. ],
  32. tooltip: "点击弹出菜单",
  33. onSelected: (String result) {
  34. switch (result) {
  35. case "1":
  36. print('分享');
  37. break;
  38. case "2":
  39. print('设置');
  40. break;
  41. }
  42. },
  43. onCanceled: () {
  44. print("取消");
  45. },
  46. ),
  47. ]
  48. ),
  49. body: Container()
  50. );
  51. }
  52. }

PopupMenuDivider 为菜单项之间的分隔符

水平排列的按钮组

ButtonBar: 水平排列的按钮组,示例:
009.png

  1. ButtonBar(
  2. alignment: MainAxisAlignment.spaceAround, // 布局方向,默认MainAxisAlignment.end
  3. mainAxisSize: MainAxisSize.max, // 主轴大小,默认MainAxisSize.max
  4. children: <Widget>[ // Button集合
  5. RaisedButton(child: Text('ButtonBar1', style: TextStyle(color: Colors.white),),color: Colors.blue,
  6. onPressed: ()=>{},),
  7. RaisedButton(child: Text('ButtonBar2', style: TextStyle(color: Colors.white),),color: Colors.blue,
  8. onPressed: ()=>{},),
  9. RaisedButton(child: Text('ButtonBar3', style: TextStyle(color: Colors.white),),color: Colors.blue,
  10. onPressed: ()=>{},),
  11. ],
  12. ),

InkWell

InkWell 可以创建一个包含水波效果的按钮
002.png

InkWell 可以捕获更多事件:

  • onTap
  • onDoubleTap
  • onLongPress
  • onTapCancel
  • onTapDown
  • onHighlightChanged
  • onHover

InkWell无水波纹效果的解决方案

在 InkWell 的外层再套上 Matetial 以及 Ink组件:

  1. Material(
  2. child: Ink(
  3. child:
  4. InkWell(
  5. onTap: () {
  6. // ...
  7. },
  8. child: ListTile(
  9. // ...
  10. ),
  11. ),
  12. ),
  13. )

自定义按钮组件的封装

其实写按钮组件也挺费劲的,我们可以封装一个公共按钮组件:

  1. enum ButtonType { RaisedButton, FlatButton }
  2. Widget CommonButton (
  3. title, {
  4. VoidCallback onPressed,
  5. Color bgColor: BaseStyle.mainColor, // 按钮背景色
  6. Color textColor, // 文字颜色
  7. Color splashColor: Colors.grey, // 水波颜色
  8. Color highlightColor: Colors.transparent, // 高亮颜色
  9. ButtonType type: ButtonType.RaisedButton, // 按钮类型
  10. }
  11. ) {
  12. textColor = type == ButtonType.RaisedButton ? Colors.white : BaseStyle.mainColor;
  13. if (type == ButtonType.RaisedButton) {
  14. return RaisedButton(
  15. color: bgColor,
  16. splashColor: splashColor,
  17. highlightColor: highlightColor,
  18. colorBrightness: Brightness.dark,
  19. child: Text(title, style: TextStyle(
  20. color: textColor
  21. )),
  22. onPressed: () {
  23. if (onPressed != null) {
  24. onPressed();
  25. }
  26. },
  27. );
  28. } else if (type == ButtonType.FlatButton) {
  29. return FlatButton(
  30. child: new Text(title, style: TextStyle(
  31. color: textColor
  32. )),
  33. onPressed: () {
  34. if (onPressed != null) {
  35. onPressed();
  36. }
  37. },
  38. );
  39. }
  40. }

使用方式:

  1. // RaisedButton
  2. CommonButton('取消', onPressed: () {
  3. Navigator.of(context).pop('1');
  4. }),
  5. // FlatButton
  6. CommonButton('取消', type: ButtonType.FlatButton, onPressed: () {
  7. Navigator.of(context).pop('1');
  8. }),

其他按钮

三、图片

从项目中加载图片

如果图片是存放于项目之中, 需要先在 pubspec.yaml 中的flutter部分添加如下内容:

  1. flutter:
  2. assets:
  3. - assets/imgs/avatar.png

其中 assets 是位于项目根目录而不是 lib 文件夹

使用的时候:

  1. Image(
  2. image: AssetImage("assets/imgs/avatar.png"),
  3. width: 60,
  4. height: 60,
  5. );
  6. // 或:
  7. Image.asset("assets/imgs/avatar.png", width: 60, height: 60,)

加载网络图片

  1. Image(
  2. image: NetworkImage(
  3. "https://avatars1.githubusercontent.com/u/13745132?s=460&v=4"),
  4. width: 100.0,
  5. )
  6. // 或:
  7. Image.network(
  8. "https://avatars1.githubusercontent.com/u/13745132?s=460&v=4",
  9. width: 100.0,
  10. )

如果只设置width、height的其中一个,那么另一个属性默认会按比例缩放

加载图片文件

可以从相册或相机中获取图片, 然后用 Image 加载:

  1. File _image;
  2. // 拍照
  3. Future getImage() async {
  4. try {
  5. var image = await ImagePicker.pickImage(source: ImageSource.gallery);
  6. if (image != null) {
  7. setState(() {
  8. _image = image;
  9. });
  10. }
  11. } catch (e) {}
  12. }
  13. GestureDetector(
  14. onTap: getImage,
  15. child: Image.file(_image, width: 100, height: 100,),
  16. )

这里用到了 image_picker 进行图片获取

Image

Image 的定义:

  1. const Image({
  2. ...
  3. this.width, //图片的宽
  4. this.height, //图片高度
  5. this.color, //图片的混合色值
  6. this.colorBlendMode, //混合模式
  7. this.fit,//缩放模式
  8. this.alignment = Alignment.center, //对齐方式
  9. this.repeat = ImageRepeat.noRepeat, //重复方式
  10. ...
  11. })

fit

该属性用于在图片的显示空间和图片本身大小不同时指定图片的适应模式。适应模式是在BoxFit中定义,它是一个枚举类型,有如下值可选:

  • fill:会拉伸填充满显示空间,图片本身长宽比会发生变化,图片会变形。
  • cover:会按图片的长宽比放大后居中填满显示空间,图片不会变形,超出显示空间部分会被剪裁。
  • contain:这是图片的默认适应规则,图片会在保证图片本身长宽比不变的情况下缩放以适应当前显示空间,图片不会变形。
  • fitWidth:图片的宽度会缩放到显示空间的宽度,高度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁。
  • fitHeight:图片的高度会缩放到显示空间的高度,宽度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁。
  • none:图片没有适应策略,会在显示空间内显示图片,如果图片比显示空间大,则显示空间只会显示图片中间部分。

color 和 colorBlendMode

在图片绘制时可以对每一个像素进行颜色混合处理,color指定混合色,而colorBlendMode指定混合模式, 示例:

  1. Image(
  2. image: AssetImage("images/avatar.png"),
  3. width: 100.0,
  4. color: Colors.blue,
  5. colorBlendMode: BlendMode.difference,
  6. );

repeat

当图片本身大小小于显示空间时,指定图片的重复规则。

  • ImageRepeat.noRepeat 默认
  • ImageRepeat.repeat
  • ImageRepeat.repeatX
  • ImageRepeat.repeatY

相关的第三方图片库

四、图标

Flutter中,可以像Web开发一样使用iconfont,iconfont即“字体图标”,它是将图标做成字体文件,然后通过指定不同的字符而显示不同的图片。

在字体文件中,每一个字符都对应一个位码,而每一个位码对应一个显示字形,不同的字体就是指字形不同,即字符对应的字形是不同的。而在iconfont中,只是将位码对应的字形做成了图标,所以不同的字符最终就会渲染成不同的图标。

在Flutter开发中,iconfont和图片相比有如下优势:

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

使用Material Design字体图标

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

  1. flutter:
  2. uses-material-design: true

Material Design所有图标可以在其官网查看:https://material.io/tools/icons/

使用方式
通过Text组件直接指定fontFamily渲染:

  1. Text('\uE914 \uE000 \uE90D',
  2. style: TextStyle(
  3. fontFamily: "MaterialIcons",
  4. fontSize: 24.0,
  5. color: Colors.green
  6. ),
  7. )

通过Icon组件渲染:

  1. Row(
  2. mainAxisAlignment: MainAxisAlignment.center,
  3. children: <Widget>[
  4. Icon(Icons.accessible, color: Colors.green,),
  5. Icon(Icons.error, color: Colors.green,),
  6. Icon(Icons.fingerprint, color: Colors.green, size: 20),
  7. ],
  8. )

图标按钮

使用 IconButton 可以创建一个带图标的按钮, 长按可以出现提示文本 (tooltip)

  1. IconButton(
  2. icon: Icon(Icons.volume_up),
  3. tooltip: 'mute',
  4. onPressed: () {},
  5. )

使用自定义字体图标

  1. 导入字体图标文件;这一步和导入字体文件相同,假设我们的字体图标文件保存在项目根目录下,路径为”fonts/iconfont.ttf”:

    1. fonts:
    2. - family: myIcon #指定一个字体名
    3. fonts:
    4. - asset: fonts/iconfont.ttf
  2. 为了使用方便,我们定义一个MyIcons类,功能和Icons类一样:将字体文件中的所有图标都定义成静态变量:

myIcons.dart

  1. class MyIcons{
  2. // book 图标
  3. static const IconData book = const IconData(
  4. 0xe614,
  5. fontFamily: 'myIcon',
  6. matchTextDirection: true
  7. );
  8. // 微信图标
  9. static const IconData wechat = const IconData(
  10. 0xec7d,
  11. fontFamily: 'myIcon',
  12. matchTextDirection: true
  13. );
  14. }

:::warning 配置完之后,一定要执行flutter packages get命令以及重新编译项目,否则字体文件无法使用。 :::

  1. 使用 ```dart import ‘./myIcons.dart’;

Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(MyIcons.book,color: Colors.purple,), Icon(MyIcons.wechat,color: Colors.green,), ], ) ```

参考资料