Flutter 经典控件学习(文本、图片、按钮)

前言

在此之前,花费了很长时间学习了视图数据流转机制、底层渲染方案、视图更新策略等知识,都是构成一个 UI 框架的根本,看似枯燥,却往往具有最长久的生命力。新框架每年层出不穷,可是扒下那层炫酷的“外衣”,里面其实还是那些最基础的知识和原理。

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

在对视图的基础知识有了整体印象后,再来学习 Flutter 视图系统提供所提供的 UI 控件,就会事半功倍。作为一个 UI 框架,与 Android、iOS 类似的,Flutter 自然也提供了很多 UI 控件。而文本、图片和按钮则是这些不同的 UI 框架中构建视图都要用到的三个最基础的控件。

(一)文本控件

在 Flutter 中,文本展示是通过 Text 控件实现的。

Text 支持两种类型的文本展示,一个是默认的展示单一样式的文本 Text,另一个是支持多种混合样式的富文本 Text.rich。

(1)单一样式的文本 Text

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

  • 控制整体文本布局的参数,如文本对齐方式 textAlign、文本排版方向 textDirection,文本显示最大行数 maxLines、文本截断规则 overflow 等等,这些都是构造函数中的参数;
  • 控制文本展示样式的参数,如字体名称 fontFamily、字体大小 fontSize、文本颜色 color、文本阴影 shadows 等等,这些参数被统一封装到了构造函数中的参数 style 中。
Text(
    'Hello World',
    textAlign: TextAlign.center, // 显示居中
    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: Colors.red) // 20号红色粗体
)
单一样式文本 Text
(2)多种混合展示样式

混合展示样式与单一样式的关键区别在于分片,即如何把一段字符串分为几个片段来管理,给每个片段单独设置样式。在 Flutter 中使用 TextSpan。

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

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: 'Hello', style: blackStyle),
              TextSpan(text: 'World', style: redStyle)
            ]),
            textAlign: TextAlign.center,
          ),
多种混合样式富文本 Text.rich

(二)图片

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

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

除了可以根据图片的显示方式设置不同的图片源之外,图片的构造方法还提供了填充模式 fit、拉伸模式 centerSlice、重复模式 repeat 等属性,可以针对图片与目标区域的宽高比差异制定排版模式。

在加载网络图片的时候,为了提升用户的等待体验,我们往往会加入占位图、加载动画等元素,这时候我需要用到 FadeInImage 控件。

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

 FadeInImage.assetNetwork(
          placeholder: 'images/loading.gif',
          image: '[https://avatars2.githubusercontent.com/u/30656290?s=400&u=09c8f2272dc7055321ef0a5a5350ddf1c6f3a293&v=4](https://avatars2.githubusercontent.com/u/30656290?s=400&u=09c8f2272dc7055321ef0a5a5350ddf1c6f3a293&v=4)
',
          fit: BoxFit.cover,
          width: 200,
          height: 200,
        )
FadeInImage 占位图

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

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

图片加载流程

值得注意的是,ImageCache 使用 LRU(Least Recently Ised,最近最少使用)算法进行缓存更新策略,并且默认最多储存 1000 张图片,最大缓存限制为 100 MB,当限定的空间已存满数据时,把最久没有被访问到的图片清除。图片缓存只会在运行期间生效,也就是只缓存在内存中。如果想要支持缓存到文件系统,可以使用 Flutter 第三方的 CachedNetworkImage 控件。

CachedNetworkImage 的使用方法与 Image 类似,除了支持图片缓存外,还提供了比 FadeImage 更强大的加载过程占位与加载错误占位,可以支持比用图片占位更灵活的自动以控件占位。


(三)按钮

通过按钮,响应用户的交互事件。Flutter 提供了三个基本的按钮控件,FlatButton 、RaisedButton 和 FloatingActionButton。

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

示例代码,纵列的布局中,分别排列三个样式按钮:

body: Column(
        children: <Widget>[
          FlatButton(
            onPressed: () => print('FlatButton pressed'),
            child: Text('Btn1'),
          ),
          RaisedButton(
            onPressed: () => print('RaisedButton pressed'),
            child: Text('Btn2'),
          ),
          FloatingActionButton(
            onPressed: () => print('FloatingActionButton pressed'),
            child: Text('Btn3'),
          )
        ],
      ),
按钮效果

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

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

虽然我们可以通过 child 参数来控制按钮控件的基本样式,但是系统默认的样式还是太单调了。因此通常情况下,我们还是会进行控件样式定制。

与 Text 控件类似,按钮控件也提供了丰富的样式定制功能,比如背景颜色 color、按钮形状 shape、主题颜色 colorBrightness,等等。

示例代码:

body: FlatButton(
    // 设置背景色为粉色
    color: Colors.pink,
    // 设置斜角矩形边框
    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,保证按钮文字颜色为深色。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342