Flutter的文本、图片和按钮使用

像视图数据流转机制、底层渲染方案、视图更新策略等知识,都是构成一个UI框架的根本,看似枯燥,却往往具有最长久的生命力。

因此, 只有把这些最基础的知识弄明白,修好内功,才能触类旁通,由点及面形成自己知识体系,也能在框架之上思考应用层构建视图实现的合理性。

对视图基础有整体印象后,再学习Flutter视图系统所提供的UI控件。作为UI框架,与Android、iOS和React类似,Flutter也提供很多UI控件。而文本、图片和按钮则是这些不同UI框架中构建视图都要用到的最基本控件。

1 文本控件

文本是视图系统中的常见控件,用来显示一段特定样式的字符串,就比如Android里的TextView、iOS中的UILabel。而在Flutter中,文本展示是通过Text控件实现的。

Text支持两种类型文本展示:

  • 默认的展示单一样式的文本Text
  • 支持多种混合样式的富文本Text.rich

1.1 使用单一样式的文本Text

单一样式文本Text的初始化,要传入需展示的字符串。而这字符串的具体展示效果,受构造函数其他参数控制。这些参数分为:

  • 控制整体文本布局的参数,如文本对齐方式textAlign、文本排版方向textDirection,文本显示最大行数maxLines、文本截断规则overflow等都是构造函数中的参数
  • 控制文本展示样式的参数,如字体名称fontFamily、字体大小fontSize、文本颜色color、文本阴影shadows等等,这些参数被统一封装到了构造函数中的参数style

展示单一样式的文本Text

居中布局、20号红色粗体展示样式的字符串:

Text(
  '文本是视图系统中的常见控件,用来显示一段特定样式的字符串,就比如Android里的TextView,或是iOS中的UILabel。',
  textAlign: TextAlign.center,//居中显示
  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.red),//20号红色粗体展示
);

运行效果如下图所示:

图1:单一样式文本Text示例

在一段字符串中支持多种混合展示样式

与单一样式的关键区别在于分片,即如何把一段字符串分为几个片段,给每个片段单独设置样式:

  • Android中使用SpannableString实现
  • iOS中使用NSAttributedString来实现
  • Flutter也有类似概念TextSpan

TextSpan定义一个字符串片段该如何控制其展示样式,而将这些有独立展示样式的字符串组装在一起,则能支持混合样式的富文本展示。

分别定义黑色、红色两种展示样式,随后把一段字符串分成4个片段,并设置不同展示样式:

TextStyle blackStyle = TextStyle(fontWeight: FontWeight.normal, fontSize: 20, color: Colors.black); //黑色样式

TextStyle redStyle = TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.red); //红色样式

Text.rich(
    TextSpan(
        children: <TextSpan>[
          TextSpan(text:'文本是视图系统中常见的控件,它用来显示一段特定样式的字符串,类似', style: redStyle), //第1个片段,红色样式
          TextSpan(text:'Android', style: blackStyle), //第1个片段,黑色样式
          TextSpan(text:'中的', style:redStyle), //第1个片段,红色样式
          TextSpan(text:'TextView', style: blackStyle) //第1个片段,黑色样式
        ]),
  textAlign: TextAlign.center,
);

运行效果,如下图所示:

图2:混合样式富文本Text.rich示例

再看Flutter中的图片控件Image。

2 图片

使用Image可让我们向用户展示一张图片。图片显示方式很多,如资源图片、网络图片、文件图片等,图片格式各不相同,在Flutter也有多种方式加载不同形式、支持不同格式图片:

  • 加载本地资源图片,如Image.asset(‘images/logo.png’)
  • 加载本地(File文件)图片,如Image.file(new File(’/storage/xxx/xxx/test.jpg’))
  • 加载网络图片,如Image.network( 'http://xxx/xxx/test.gif')

除了根据图片显示方式设置不同图片源,图片构造方法还提供:

  • 填充模式fit
  • 拉伸模式centerSlice
  • 重复模式repeat等属性

可针对图片与目标区域的宽高比差异制定排版模式。

这和Android中ImageView、iOS里的UIImageView的属性都类似。可参考官方文档中的 Image的构造函数 部分,去查看Image控件具体使用方法。

FadeInImage控件

加载网络图片,为提升用户等待体验,会加占位图、加载动画等元素,但默认Image.network构造方法不支持这些高级功能,FadeInImage控件就有用了。

FadeInImage控件提供图片占位功能,并支持在图片加载完成时淡入淡出视觉效果。由于Image支持gif格式,还可将一些炫酷加载动画作占位图。

加载大图片时,将一张loading的gif作为占位图展示给用户:

FadeInImage.assetNetwork(
  placeholder: 'assets/loading.gif', //gif占位
  image: 'https://xxx/xxx/xxx.jpg',
  fit: BoxFit.cover, //图片拉伸模式
  width: 200,
  height: 200,
)
图3:FadeInImage占位图

Image控件需根据图片资源异步加载情况,决定显示效果,因此是StatefulWidget。图片加载过程由ImageProvider触发,而ImageProvider表示异步获取图片数据的操作,可从资源、文件和网络等不同渠道获取图片。

  • ImageProvider根据_ImageState中传递的图片配置生成对应的图片缓存key
  • 然后去ImageCache查找是否有对应图片缓存:
    • 有,通知_ImageState刷新UI
    • 没有,启动ImageStream开始异步加载,加载完毕后,更新缓存
  • 最后,通知_ImageState刷新UI

图片展示流程:

图4:图片加载流程

ImageCache使用LRU缓存更新策略,默认最多存储1000张图片,最大缓存限制100MB,当限定空间存满数据,把最久没有被访问到的图片清除。图片 缓存只会在运行期间生效,也就是只缓存在内存中。要支持缓存到文件系统,可使用 CachedNetworkImage 控件。

CachedNetworkImage使用类似Image,除了支持图片缓存,还提供比FadeInImage更强大的加载过程占位与加载错误占位,支持比用图片占位更灵活的自定义控件占位。

加载图片时,不仅给用户展示占位的转圈loading,还提供错误图兜底,以备图片加载出错:

CachedNetworkImage(
        imageUrl: "http://xxx/xxx/jpg",
        placeholder: (context, url) => CircularProgressIndicator(),
        errorWidget: (context, url, error) => Icon(Icons.error),
     )

3 按钮

可响应用户交互事件。Flutter提供三个基本按钮控件:

  • FloatingActionButton:圆形按钮,一般在屏幕内容前面,处理界面中最常用、最基础用户动作。计数器示例的“+”悬浮按钮就是FloatingActionButton
  • RaisedButton:凸起按钮,默认带灰色背景,被点击后灰色背景会加深
  • FlatButton:扁平化按钮,默认透明背景,被点击后会呈现灰色背景

按钮控件使用方法唯一区别只是默认样式不同。

分别定义FloatingActionButton、FlatButton与RaisedButton,功能完全一样,点击时打印文字:

FloatingActionButton(onPressed: () => print('FloatingActionButton pressed'),child: Text('Btn'),);
FlatButton(onPressed: () => print('FlatButton pressed'),child: Text('Btn'),);
RaisedButton(onPressed: () => print('RaisedButton pressed'),child: Text('Btn'),);

按钮控件:

image-20230623145628607

既然是按钮,因此除了控制基本样式,还要响应用户点击行为。这就对应按钮控件中的两个最重要参数:

  • onPressed参数用于设置点击回调,告诉Flutter在按钮被点击时通知我们。若onPressed参数为空,则按钮会处于禁用状态,不响应用户点击
  • child参数用于设置按钮内容,告诉Flutter控件应长成啥样,即控制按钮控件的基本样式。child可接收任意Widget,如上面例子中传入的Text,此外还可传入Image等控件

虽可通过child参数控制按钮控件基本样式,但系统默认样式太单调,通常进行控件样式定制。与Text控件类似,按钮控件也提供丰富样式定制功能,如背景颜色color、按钮形状shape、主题颜色colorBrightness等。

以FlatButton为例介绍按钮样式定制:

FlatButton(
    color: Colors.yellow, //设置背景色为黄色
    shape:BeveledRectangleBorder(borderRadius: BorderRadius.circular(20.0)), //设置斜角矩形边框
    colorBrightness: Brightness.light, //确保文字按钮为深色
    onPressed: () => print('FlatButton pressed'),
    child: Row(children: <Widget>[Icon(Icons.add), Text("Add")],)
)

将一个加号Icon与文本组合,定义按钮基本外观;随后通过shape指定其外形为斜角矩形边框,并将按钮背景色设为黄色。

因为按钮背景颜色是浅色的,为避免按钮文字看不清楚,我们通过设置按钮主题colorBrightness为Brightness.light,保证按钮文字颜色为深色。展示效果:

图6:按钮控件定制外观

4 总结

UI控件是构建一个视图的基本元素,而文本、图片和按钮则是其中最经典的控件。

首先,认识支持单一样式和混合样式两种类型文本展示控件Text:

  • 通过TextStyle控制字符串的展示样式,其他参数控制文本布局,实现单一样式文本展示
  • 通过TextSpan将字符串分割为若干片段,对每个片段单独设置样式后组装,实现支持混合样式富文本展示

支持多种图片源加载方式的图片控件Image。Image内部通过ImageProvider根据缓存状态,触发异步加载流程,通知_ImageState刷新UI。不过,由于图片缓存是内存缓存,因此只在运行期间生效。要支持缓存到文件系统,使用CachedNetworkImage。

最后学习按钮控件。Flutter提供多种按钮控件,使用方法类似。控件初始化的child参数用于设置按钮长什么样,而onPressed参数则用于设置点击回调。与Text类似,按钮内部也有丰富UI定制接口。

UI基本信息表达,Flutter经典控件与原生Android、iOS系统提供的控件无本质区别。但自定义控件样式,Flutter的这些经典控件提供强大简洁扩展能力,快速开发功能复杂、样式丰富页面。

5 FAQ

阅读Flutter SDK中Text、Image、FadeInImage,以及按钮控件FloatingActionButton、FlatButton与RaisedButton的源码,在build函数中找出在内部真正承载其视觉功能的控件。发现什么现象?

在阅读Flutter SDK中Text、Image、FadeInImage、FloatingActionButton、FlatButton和RaisedButton的源码时,可以发现它们的build函数中都有一个内部真正承载其视觉功能的控件。

  • 对于Text控件,其内部真正承载其视觉功能的控件为RichText。
  • 对于Image控件,其内部真正承载其视觉功能的控件为RawImage。
  • 对于FadeInImage控件,其内部真正承载其视觉功能的控件为AnimatedOpacity和RawImage。
  • 对于FloatingActionButton控件,其内部真正承载其视觉功能的控件为Material和InkResponse。
  • 对于FlatButton控件,其内部真正承载其视觉功能的控件为Material和InkWell。
  • 对于RaisedButton控件,其内部真正承载其视觉功能的控件为Material和InkResponse。

这些控件都是Flutter框架中提供的基础控件,用于实现各种不同的视觉效果。在这些控件的build函数中,会根据不同的属性值来创建这些基础控件,并将它们组合在一起,从而实现所需的视觉效果。

再分享我整理汇总的一些 Java 面试相关资料(亲自验证,严谨科学!别再看网上误导人的垃圾面试题!!!),助你拿到更多 offer!

点击获取更多经典必读电子书!

2023年最新Java学习路线一条龙:

再给大家推荐一个学习 Java 和准备Java 面试的公众号【JavaEdge】(强烈推荐!)

猜你喜欢

转载自blog.csdn.net/qq_33589510/article/details/131351330
今日推荐