Flutter

本文深入解析Flutter中的各种Widget,包括Text、Button、Image等基础组件,Row、Column等布局类Widget,以及Container等容器类Widget的使用技巧。文章还介绍了如何通过TextSpan进行文本样式定制,以及如何利用Widget构建复杂UI。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Widget

1.1 基础类Widget

  • Text
构造方式说明
Text(data,{...})data:文本文案,{...}:可选命名参数
Text(textSpan,{...})textSpan:文本片段,{...}:可选命名参数

第一个相对简单,满足一般使用场景。
第二个更加灵活,可对文本文案做一些深度定制,比如添加中划线、下划线、一部分文案改颜色这样的需求,就必须使用textSpan对文本做处理了。
下面按照由简单到复杂的步骤逐步使用Text来呈现不一样的文本信息
首先,假设有这么一段文本,需要展示在屏幕上:

String data = "2018年江苏省GDP增长情况:苏州涨幅最高(8%),徐州增速最快(2%提升到6%),镇江出现下滑(-3%),详细信息参考官网。" 
复制代码

不做任何处理的文案展示

@override
  Widget build(BuildContext context) {

    String data = "2018年江苏省GDP增长情况:苏州涨幅最高(8%),徐州增速最快(2%提升到6%),镇江出现下滑(-3%),详细信息参考官网。";
    return Scaffold(
      appBar: AppBar(
        title: Text("Text"),
      ),
      body: new Column(
        mainAxisSize: MainAxisSize.max, //主轴方向充满屏幕
        mainAxisAlignment: MainAxisAlignment.start, //子widget左对齐
        crossAxisAlignment: CrossAxisAlignment.start, //子widget在纵轴方向居中对齐
        children: <Widget>[
          Text(data ),
        ],
      ),
    );
  }
复制代码

老板说:最多显示一行,显示不下的地方用...结尾,必须字体需要放大 加粗
这个时候就需要使用构造函数中的命名参数来设置了

@override
  Widget build(BuildContext context) {

    String data = "2018年江苏省GDP增长情况:苏州涨幅最高(8%),徐州增速最快(2%提升到6%),镇江出现下滑(-3%),详细信息参考官网。";
    return Scaffold(
      body: new Column(
        children: <Widget>[
          Text(data ,
            maxLines: 1, //最多显示1行
            overflow: TextOverflow.ellipsis, //末尾截断
            style: TextStyle(
              fontSize: 16, //字体大小
              fontWeight: FontWeight.bold //加粗
          ),),
        ],
      ),
    );
  }
复制代码

老板又说:这样显示没有突出点。需要将苏州标红,镇江标绿,题干加粗,最后可以点击打开官网......
一段话需要设置这么多的状态,这就需要用到第二种构造方式了:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new Column(
        children: <Widget>[
          Text.rich(
            TextSpan(children: [
              TextSpan(
                  text: "2018年江苏省GDP增长情况: ",
                  style: TextStyle(fontWeight: FontWeight.bold)),
              TextSpan(
                text: "苏州涨幅最高",
              ),
              TextSpan(
                text: "(8%)",
                style: TextStyle(color: Colors.deepOrange), //颜色设置为红色
              ),
              TextSpan(
                text: ",徐州增速最快",
              ),
              TextSpan(
                text: "(2%提升到6%)",
                style: TextStyle(color: Colors.yellow), //颜色设置为黄色
              ),
              TextSpan(
                text: ",镇江出现下滑",
              ),
              TextSpan(
                text: "(-3%), ",
                style: TextStyle(color: Colors.green), //颜色设置为绿色
              ),
              TextSpan(
                  text: "详细信息参考官网。",
                  style: TextStyle(
                      color: Colors.grey, decoration: TextDecoration.underline),//颜色设置为灰色,下划线
                  recognizer: new TapGestureRecognizer() //设置点击事件
                    ..onTap = () {
                      print("打开官网");
                    }),
            ]),
          ),
        ],
      ),
    );
  }
复制代码

Text的命名参数有很多,这里就不一一举例实现了。万变不离其宗,所有的变化都是通过2个构造函数中的textSpan和可选命名构造函数实现的,附一张Text可选命名参数的简要说明:

参数名含义类型说明
style字体属性TextStyle通过对象TextStyle获取,TextStyle构造函数也接收一堆可选命名参数
textAlign文字对其方式TextAlign通过枚举TextAlign获取
textDirection文字方向TextDirection通过枚举TextDirection获取,多数情况下不需要关心这个参数
locale国际化语言相关Locale
softWrap是否自动换行bool若为false,文字将不考虑容器大小,单行显示,超出屏幕部分将默认截断处理
overflow文字长度超过容器的处理方式TextOverflow通过枚举TextOverflow获取
textScaleFactor相对于当前字体大小的缩放因子double默认值将为1.0
maxLines文字最大行数int默认不限制
semanticsLabel图像的语义描述,用于向Andoid上的TalkBack和iOS上的VoiceOver提供图像描述String没搞明白这个参数
  • Button
    Button比较简单,这里列举三个最简单的实现:
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Button"),
      ),
      body: new Column(
        children: <Widget>[
          RaisedButton(
            child: Text("RaisedButton"),
            onPressed: () {
                //点击事件监听
            },
          ),
          FlatButton(
            child: Text("FlatButton"),
            onPressed: () {
                //点击事件监听
            },
          ),
          OutlineButton(
            child: Text("OutlineButton"),
            onPressed: () {
                //点击事件监听
            },
          ),
        ],
      ),
    );
  }
复制代码
  • Image
  1. 通过assets加载图片:

    • step1: 项目根目录新建存放图片的目录。 我的目录名为images(名称随意)
    • step2: 在pubspec.yml中配置图片
    • step3: 代码中获取图片
  2. 网络下载图片

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Image & Icon"),
      ),
      body: new Column(
        children: <Widget>[
          Image(  //加载asset图片,大小100*100
            width: 100,
            height: 100,
            image: AssetImage("images/test_img.jpg"),
          ),
          Image( //加载网络图片,大小200*200
            width: 200,
            height: 200,
            image: NetworkImage("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1547637189125&di=36a042b71b1e6b4ccd80adca6d8f05ff&imgtype=0&src=http%3A%2F%2Fimg.bimg.126.net%2Fphoto%2FZZ5EGyuUCp9hBPk6_s4Ehg%3D%3D%2F5727171351132208489.jpg"), 
          ),
        ],
      ),
    );
  }
复制代码

效果图:

  • Icon
  • Switch
  • Checkbox。
  • TextField

1.2 布局类Widget

布局类widget一般包含多个children,布局类widget一般是描述children的排列方式

Widget含义说明
Row行布局,一行多列
WrapRow默认只有一行,如果超出屏幕不会折行。通过Wrap可以让Row溢出部分自动折行
Column列布局,一列多行
Flow使用较少
Flex可以定义权重的Row或者Column(个人觉得类似android中的weight属性)Flex需要和Expanded配合使用
Stack层叠布局,类似FrameLayoutStack本身有属性设置children的默认对其方式,也可以使用Positioned准确定义child的位置
  • 共有参数
参数名含义备注
textDirection表示水平方向子widget的布局顺序(是从左往右还是从右往左),默认为系统当前Locale环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)。
mainAxisSize表示Row在主轴(水平)方向占用的空间,默认是MainAxisSize.max,表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度;而MainAxisSize.min表示尽可能少的占用水平空间,当子widgets没有占满水平剩余空间,则Row的实际宽度等于所有子widgets占用的的水平空间
mainAxisAlignment表示子Widgets在Row所占用的水平空间内对齐方式,如果mainAxisSize值为MainAxisSize.min,则此属性无意义,因为子widgets的宽度等于Row的宽度。只有当mainAxisSize的值为MainAxisSize.max时,此属性才有意义,MainAxisAlignment.start表示沿textDirection的初始方向对齐,如textDirection取值为TextDirection.ltr时,则MainAxisAlignment.start表示左对齐,textDirection取值为TextDirection.rtl时表示从右对齐。而MainAxisAlignment.end和MainAxisAlignment.start正好相反;MainAxisAlignment.center表示居中对齐。读者可以这么理解:textDirection是mainAxisAlignment的参考系。
verticalDirection表示Row纵轴(垂直)的对齐方向,默认是VerticalDirection.down,表示从上到下
crossAxisAlignment表示子Widgets在纵轴方向的对齐方式,Row的高度等于子Widgets中最高的子元素高度,它的取值和MainAxisAlignment一样(包含start、end、 center三个值),不同的是crossAxisAlignment的参考系是verticalDirection,即verticalDirection值为VerticalDirection.down时crossAxisAlignment.start指顶部对齐,verticalDirection值为VerticalDirection.up时,crossAxisAlignment.start指底部对齐;而crossAxisAlignment.end和crossAxisAlignment.start正好相反
children子Widgets数组。
  • Wrap特有参数
参数名含义备注
spacing主轴方向子widget的间距
runSpacing纵轴方向的间距
runAlignment纵轴方向的对齐方式
  • Stack特有参数
参数名含义备注
alignment此参数决定如何去对齐没有定位(没有使用Positioned)或部分定位的子widget。所谓部分定位,在这里特指没有在某一个轴上定位:left、right为横轴,top、bottom为纵轴,只要包含某个轴上的一个定位属性就算在该轴上有定位。
fix此参数用于决定没有定位的子widget如何去适应Stack的大小。StackFit.loose表示使用子widget的大小,StackFit.expand表示扩伸到Stack的大小。
overflow此属性决定如何显示超出Stack显示空间的子widget,值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。

1.3 容器类Widget

容器类widget一般只有1个child。容器的描述一般是对child的包装:添加一些修饰(补白或背景色等)、变换(旋转或剪裁等)、或限制(大小等)。

参数名含义备注
Padding给其子节点添加补白(填充)EdgeInsets.all .fromLTRB .only .symmetric
ConstrainedBoxConstrainedBox用于对齐子widget添加额外的约束宽高、最小宽高、最大宽高
SizedBox可以看出是一个固定了宽高的ConstrainedBoxConstrainedBox如果有多重限制会发生什么?
UnconstrainedBoxUnconstrainedBox不会对子Widget产生任何限制,它允许其子Widget按照其本身大小绘制会很少直接使用此widget
DecoratedBoxDecoratedBox可以在其子widget绘制前(或后)绘制一个装饰Decoration(如背景、前景、边框、渐变、阴影等)
Transform平移、旋转、缩放等有一个RotatedBox,需要区分和 Transform.rotate的区别,一个在绘制时起作用,一个在布局时起作用
Container可以看成是其他容器类widget的一个组合Container可以实现同时需要填充、约束、装饰、变换等场景
Scaffold一个路由页的骨架,可以非常容易的拼装出一个完整的页面AppBar、抽屉、顶部导航、底部导航、悬浮按钮等等

1.4 功能类Widget

1.5 事件处理与监听

1.6 动画

1.7 自定义

其他

flutter的一些开源库:

  • loading态widget: https://pub.flutter-io.cn/packages/flutter_spinkit

转载于:https://juejin.im/post/5c3e98a0518825260c5d006a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值