likes
comments
collection
share

Flutter 系列(四):Flutter 常用 Widget 二

作者站长头像
站长
· 阅读数 8

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

前言

很高兴遇见你~

在本系列的上一篇文章中,我们介绍了 Flutter 特点以及一些常用的 Widget:MaterialApp,Scaffold,AppBar,Center,Container,Text。还没有看过上一篇文章的朋友,建议先去阅读 Flutter 系列(三):Flutter 特点及常用 Widget 介绍。接下来我们继续对 Flutter Widget 进行学习

下面我会通过:效果展示 -> Widget 讲解 -> 代码实现的方式对 Widget 进行介绍,最后在通过 Widget 组合编写一个综合的案例

一、Flutter Widget 之 Image

Image 是 Flutter 给我们提供显示图片的 Widget

先看一眼使用 Image 实现的效果

1.1、Image 效果展示

Flutter 系列(四):Flutter 常用 Widget 二

刘亦菲的圆形图片😄,美爆了。言归正传,大家可以先想一下怎么去实现?

1.2、Image 介绍

Image 组件有很多构造方法,这里给大家讲两个常用的:

1、Image.network :加载远程图片

2、Image.asset :加载本地图片

上面这两个属于 Image 的命名构造方法,对命名构造方法还不熟悉的赶紧先去看一下我的另一篇文章传送门

1.2.1、Image.network 加载远程图片

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text("Flutter Image Widget"),//设置标题栏标题
        elevation: 30,//设置标题栏阴影
      ),
      body: MyBodyPage() //自定义 Widget
    ),
  ));
}

class MyBodyPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Image.network("https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg");
  }
}

上述代码很简单,就是使用 Image.network 传入一张图片 url ,这样就可以将这张网络图片显示出来了:

Flutter 系列(四):Flutter 常用 Widget 二

1.2.2、Image.asset 加载本地图片

加载本地图片稍微复杂一些

1、新建图片目录,引入图片资源

Flutter 系列(四):Flutter 常用 Widget 二

我们新建了 images 文件夹,并在 images 下放入了图片资源,又新建了 2.0x 和 3.0x 文件夹分别对应 2 倍图和 3 倍图,这样就能保证不同手机分辨率的手机加载对应文件夹下的图片资源

2、打开 pubspec.yaml 配置文件声明一下我们添加的图片

Flutter 系列(四):Flutter 常用 Widget 二

3、最后在代码中使用就可以了

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text("Flutter Image Widget"),//设置标题栏标题
        elevation: 30,//设置标题栏阴影
      ),
      body: MyBodyPage() //自定义 Widget
    ),
  ));
}

class MyBodyPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Image.asset("images/ic_launcher_round.png");
  }
}

效果如下:

Flutter 系列(四):Flutter 常用 Widget 二

1.2.3、Image 常用属性

名称类型说明
alignmentAlignment图片的对齐方式
color 和 colorBlendMode设置图片的背景颜色,通常和 colorBlendMode 配合一起使用,这样可以使图片颜色和背景色混合
fitBoxFitfit 属性用来控制图片的拉伸和挤压,这都是根据父容器来的:BoxFit.fill:全图显示,图片会被拉伸,并充满父容器BoxFit.contain:全图显示,显示原比例,可能会有空隙BoxFit.cover:显示可能拉伸,可能裁切,充满(图片要充满整个容器,还不变形)BoxFit.fitWidth:宽度充满(横向充满),显示可能拉伸, 可能裁切BoxFit.fitHeight:高度充满(竖向充满),显示可能拉 伸,可能裁切BoxFit.scaleDown:效果和 contain 差不多,但是此属性不允许显示超过原图片大小,可小不可大
width宽度,一般结合 ClipOval Widget 才能看到效果
height高度,一般结合 ClipOval Widget 才能看到效果

更多属性参考:api.flutter.dev/flutter/wid…

PS:ClipOval 是一个裁剪子 Widget 为椭圆的 Widget,常用于圆形,圆角图片等

1.3、效果实现

回顾 1.1 的效果:其实就是一个居中展示的圆形图片

这里我们可以使用 Center 进行居中,然后使用 Image + ClipOval 配合相关属性实现圆形图片:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text("Flutter Image Widget"),//设置标题栏标题
        elevation: 30,//设置标题栏阴影
      ),
      body: MyBodyPage() //自定义 Widget
    ),
  ));
}

class MyBodyPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ClipOval(
        child: Image.network(
          "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
          width: 300, //设置图片的宽度为 300
          height: 300, //设置图片的高度为 300
          fit: BoxFit.cover, //设置图片等比放大,充满父容器
        ),
      ),
    );
  }
}

上述代码就实现了我们想要的效果

二、Flutter Widget 之 ListView

列表是我们项目开发中最常用的一种布局方式,Flutter 给我们提供了 ListView 来定义列表,它支持垂直和水平方向展示,通过一个属性就可以控制列表的显示方向

2.1、效果展示

Flutter 系列(四):Flutter 常用 Widget 二

2.2、ListView 介绍

2.2.1、常用属性介绍

名称类型说明
scrollDirectionAxisAxis.horizontal 水平列表 Axis.vertical 垂直列表
paddingEdgeInsetsGeometry內边距
resolvebool组件反向排序
childrenList列表元素

更多属性参考:api.flutter.dev/flutter/wid…

ListView 的 children 能嵌套各种 Widget 去实现列表 UI 效果

2.2.2、ListTile 介绍

ListTile 是一个列表 item Widget ,通常用于各种列表中,其常用的属性有:

名称类型说明
leadingWidget左侧组件
titleWidget标题
subtitleWidget副标题
trailingWidget右侧组件
onTap点击事件回调
onLongPress长按事件回调

更多属性参考:api.flutter.dev/flutter/mat…

下面我们使用 ListView + ListTile 实现一个效果:

import 'package:flutter/material.dart';

void main() {

  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text("Flutter ListView Widget"),//设置标题栏标题
        elevation: 30,//设置标题栏阴影
      ),
      body: MyBodyPage() //自定义 Widget
    ),
  ));
}

class MyBodyPage extends StatelessWidget{

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        ListTile(
          leading: Icon(Icons.search),
          title: Text("标题1"),
          subtitle: Text("描述1"),
          trailing: Icon(Icons.home),
        ),
        ListTile(
          leading: Icon(Icons.search),
          title: Text("标题2"),
          subtitle: Text("描述2"),
          trailing: Icon(Icons.home)
        ),
        ListTile(
          leading: Icon(Icons.search),
          title: Text("标题3"),
          subtitle: Text("描述3"),
          trailing: Icon(Icons.home)
        )
      ],
    );
  }
}

效果图:

Flutter 系列(四):Flutter 常用 Widget 二

2.3、效果实现

上面 2.1 展示的效果就是:ListTile + 横线作为一个 item 进行排列,如何将这两个 Widget 包装为一个整体,我们就要学习下 Column

1、Column 介绍

Column 是 Flutter 给我们提供的垂直布局 Widget,其常用属性有:

名称类型说明
mainAxisAlignmentMainAxisAlignment主轴的排序方式
crossAxisAlignmentCrossAxisAlignment次轴的排序方式
childrenList组件子元素

更多属性参考:api.flutter.dev/flutter/wid…

同样 Flutter 给我们提供了水平布局 Widget Row,常用属性和 Column 一样

2、横线我们直接使用 Divider

ok,现在就可以去实现效果图了,上面 2.2 的例子 ListView 里面的数据都是写死的,不灵活,接下来我们使用 ListView 的命名构造方法 ListView.Builder 来实现动态加载:

import 'package:flutter/material.dart';

void main() {

  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text("Flutter ListView Widget"),//设置标题栏标题
        elevation: 30,//设置标题栏阴影
      ),
      body: MyBodyPage() //自定义 Widget
    ),
  ));
}

class MyBodyPage extends StatelessWidget{

  //mock 数据:相当于 List<Map>
  var mDataList = [
    {
      "title":"标题1",
      "desc":"描述1",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题2",
      "desc":"描述2",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题3",
      "desc":"描述3",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题4",
      "desc":"描述4",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题5",
      "desc":"描述6",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
  ];

  @override
  Widget build(BuildContext context) {
    return ListView.builder(//通过 ListView.builder 实现数据的动态加载
        itemCount: mDataList.length, //item 的个数
        itemBuilder: (context, index) { //通过 itemBuilder 构建 Widget
          return Column(
            children: [ //Column 里面包装了 ListTile + Divider
              ListTile(
                leading: ClipOval( //圆形图片
                  child: Image.network(
                    mDataList[index]["image"] ?? "",
                    width: 50,
                    height: 50,
                    fit: BoxFit.cover,
                  ),
                ),
                title: Text(mDataList[index]["title"] ?? ""), //标题
                subtitle: Text(mDataList[index]["desc"] ?? ""), //副标题
              ),
              Divider() //横线
            ],
          );
        });
  }
}

上述代码就实现了我们想要的效果

三、Flutter Widget 之 GridView

GridView 是 Flutter 给我们提供的网格布局 Widget,我们快速过一下,然后实现一些效果:

GridView 创建网格列表有多种方式,主要介绍两种:

1、通过 GridView.count 实现网格布局

2、通过 GridView.builder 实现网格布局

常用属性

名称类型说明
scrollDirectionAxisAxis.horizontal 水平列表 Axis.vertical 垂直列表
paddingEdgeInsetsGeometry內边距
resolvebool组件反向排序
childrenList列表元素
crossAxisSpacingdouble水平子 Widget 之间间距
mainAxisSpacingdouble垂直子 Widget 之间间距
crossAxisCountint一行的 Widget 数量
childAspectRatiodouble子 Widget 宽高比例
gridDelegateSliverGridDelegate控制布局主要用在 GridView.builder 里面

3.1、Flutter GridView.count 实现网格布局

import 'package:flutter/material.dart';

void main() {

  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text("Flutter ListView Widget"),//设置标题栏标题
        elevation: 30,//设置标题栏阴影
      ),
      body: MyBodyPage() //自定义 Widget
    ),
  ));
}

class MyBodyPage extends StatelessWidget{

  //mock 数据
  var mDataList = [
    {
      "title":"标题1",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题2",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题3",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题4",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title":"标题5",
      "image":"https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
  ];

  List<Widget> _getListWidget() {
    var listWidget = mDataList.map((value) {
      return Container(
        decoration: //设置一个宽度为 1 绿色的边框
          BoxDecoration(border: Border.all(color: Colors.green, width: 1.0)),
        child: Column( //垂直布局里面嵌套:Expanded + SizedBox + Text + SizedBox
          children: [
            Expanded( //展开 Widget,类似 Android 里面 Linearlayout 设置权重,用在这是让图片自适应展开
              child: Image.network(// 图片
                value["image"] ?? "",
                fit: BoxFit.cover,
                width: double.infinity, //设置图片的宽度为屏幕的宽度
              ),
            ),
            SizedBox(height: 12),//设置一个高度为 12 的空白间距
            Text( // 设置文本
                value["title"] ?? "",
                textAlign: TextAlign.center,
                style: TextStyle(
                    fontSize: 20
                )
            ),
            SizedBox(height: 12),//设置一个高度为 12 的空白间距
          ],
        ),
      );
    });
    return listWidget.toList();
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 2,// 设置一行显示 Widget 数量为 2
      padding: EdgeInsets.all(20), //设置 GridView 內边距为 20
      crossAxisSpacing: 20, //设置水平子 Widget 之间的间距为 20
      mainAxisSpacing: 20,  //设置垂直子 Widget 之间的间距为 20
      children: _getListWidget() //设置子 Widget
    );
  }
}

上述代码中我们使用了两个新 Widget:Expanded,SizeBox

1、Expanded 是用于展开子 Widget 的 Widget,常用于 Row,Column 中,其 flex 属性就是用来设置权重的,类似于 Android 的 LinearLayout 设置权重

2、SizeBox 主要是用来指定一段间距的,其有两个属性,width,height。如果设置 width 就是指定宽度,如果设置 height 就是指定高度

实现效果:

Flutter 系列(四):Flutter 常用 Widget 二

3.2、Flutter GridView.builder 实现网格布局

同样的效果,我们使用 GridView.builder 来实现

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
        appBar: AppBar(
          title: Text("Flutter GridView Widget"), //设置标题栏标题
          elevation: 30, //设置标题栏阴影
        ),
        body: MyBodyPage() //自定义 Widget
        ),
  ));
}

class MyBodyPage extends StatelessWidget {
  //mock 数据
  var mDataList = [
    {
      "title": "标题1",
      "image": "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title": "标题2",
      "image": "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title": "标题3",
      "image": "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title": "标题4",
      "image": "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
    {
      "title": "标题5",
      "image": "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg"
    },
  ];

  Widget _getListWidget(context, index) {
    return Container(
      decoration: //设置一个宽度为 1 绿色的边框
          BoxDecoration(border: Border.all(color: Colors.green, width: 1.0)),
      child: Column(
        //垂直布局里面嵌套:Expanded + SizedBox + Text + SizedBox
        children: [
          Expanded(
            //扩展 Widget,类似 Android 里面 Linearlayout 设置权重,用在这是让图片自适应
            child: Image.network(
              // 图片
              mDataList[index]["image"] ?? "",
              fit: BoxFit.cover,
              width: double.infinity, //设置图片的宽度为屏幕的宽度
            ),
          ),
          SizedBox(height: 12), //设置一个高度为 12 的空白间距
          Text(
              // 设置文本
              mDataList[index]["title"] ?? "",
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 20)),
          SizedBox(height: 12), //设置一个高度为 12 的空白间距
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
        itemCount: mDataList.length,
        padding: EdgeInsets.all(20),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2, //设置一行有两个 Widget
          crossAxisSpacing: 20, //设置水平子 Widget 之间的间距为 20
          mainAxisSpacing: 20, //设置垂直子 Widget 之间的间距为 20
          childAspectRatio: 1, //设置子组件宽高比例为 1
        ),
        itemBuilder: _getListWidget //将方法作为一个参数传入
        );
  }
}

四、Flutter Widget 之 Stack

Stack 是 Fluter 提供的叠层 Widget ,类似 Android 的 FrameLayout

常用属性

名称类型说明
alignmentAlignmentGeometry配置所有子元素的显示位置
childrenList子组件

通常它会配合 Align 或 Positioned 实现定位布局

Align 常用属性

名称类型说明
alignmentAlignmentGeometry配置子元素的显示位置
childWidget子组件

Positioned 常用属性

名称类型说明
topdouble子元素距离顶部的距离
bottomdouble子元素距离底部的距离
leftdouble子元素距离左侧距离
rightdouble子元素距离右侧距离
childWidget子组件

下面我们实现如下效果:

Flutter 系列(四):Flutter 常用 Widget 二

4.1、Stack + Align 实现定位布局

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
        appBar: AppBar(
          title: Text("Flutter Stack Widget"), //设置标题栏标题
          elevation: 30, //设置标题栏阴影
        ),
        body: MyBodyPage() //自定义 Widget
        ),
  ));
}

class MyBodyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Align(
          alignment: Alignment.topLeft,//左上
          child: Container(
            width: 100,
            height: 100,
            color: Colors.red,
          ),
        ),
        Align(
          alignment: Alignment.topRight,//右上
          child: Container(
            width: 100,
            height: 100,
            color: Colors.orange,
          ),
        ),
        Align(
          alignment: Alignment.center,//中间
          child: Container(
            width: 100,
            height: 100,
            color: Colors.yellow,
          ),
        ),
        Align(
          alignment: Alignment.bottomLeft,//左下
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
          ),
        ),
        Align(
          alignment: Alignment.bottomRight,//右下
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
        )
      ],
    );
  }
}

4.2、Stack + Positioned 实现定位布局

这种方式必须指定精确的宽高,在不同分辨率的手机,可能显示会有点问题,优先还是使用 Stack + Align 实现定位布局,如果对 UI 的小偏差能忽略不计,用这个也可以

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
        appBar: AppBar(
          title: Text("Flutter Stack Widget"), //设置标题栏标题
          elevation: 30, //设置标题栏阴影
        ),
        body: MyBodyPage() //自定义 Widget
        ),
  ));
}

class MyBodyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    final screenWidth = size.width; //获取屏幕宽度
    final screenHeight = size.height; //获取屏幕高度
    return Container(
      width: double.infinity,
      height: double.infinity,
      child: Stack(
        children: [
          Positioned(//左上
            child: Container(
              width: 100,
              height: 100,
              color: Colors.red,
            ),
          ),
          Positioned(//右上
            left: screenWidth - 100,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.orange,
            ),
          ),
          Positioned(//中间
            left: screenWidth / 2 - 50,
            top: screenHeight / 2 - 90,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.yellow,
            ),
          ),
          Positioned(//左下
            top: screenHeight - 180,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.green,
            ),
          ),
          Positioned(//右下
            left: screenWidth - 100,
            top: screenHeight - 180,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.blue,
            ),
          )
        ],
      ),
    );
  }
}

五、Widget 组合之综合案例

讲综合案例之前我们介绍下 Padding:

Padding 是 Flutter 给我们提供展示内间距的 Widget,为啥要提供这个 Widget 呢?因为很多 Widget 都没有 padding 属性,这个时候我们可以用 Padding 处理与子 Widget 的內间距,其常用的属性如下:

名称类型说明
paddingEdgeInsetsGeometrypadding 值, EdgeInsets 设置填充的值
childWidget子组件

ok,接下来看下综合案例要实现的效果:

Flutter 系列(四):Flutter 常用 Widget 二

先捋一捋实现的思路:首页我们看到这个页面整体有一个内间距(Padding),元素划分为 4 块,从上到下垂直排列,可以使用 Column,在看具体的每一块:

第一块:一个黑色的长方形,可以使用 Container 实现

第二块:左边一张长图,右边先整体也看成一张图片,左右比例 2 : 1,因此我们可以使用 Row + Expanded 实现,在看右边这块整体又分上下两张图片,为了让这两张图片自适应宽度,这里我们可以使用 ListView 嵌套两个 Image

第三块:左中右三张图片,我们可以使用 Stack + Align 定位布局实现

第四块:直接使用 ListTile 实现,ListTile 的 leading 为一个圆形图片

另外还有一些小小的细节,如每一块之间的间距,横线,每一块内部的间距,这些我们使用 SizedBox,Divider 实现

通过上面的分析,我整理出了一张结构图:

Flutter 系列(四):Flutter 常用 Widget 二

接下来,我们就用代码实现一下:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Flutter Widget Combine Pricetice"),
          elevation: 30, //设置标题阴影
        ),
        body: MyHome(),
      ),
    );
  }
}

class MyHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding( //Padding 实现页面內间距
      padding: EdgeInsets.all(10),
      child: Column( //Column 实现布局垂直排列
        children: [
          Container( //Container 实现黑色长方形
              color: Colors.black,
              height: 180
          ),
          SizedBox(height: 10), //高度为 10 的间距
          Row( // Row + Expanded 实现横向布局的等比分配
            children: [
              Expanded(
                  flex: 2,
                  child: Container( //Container 嵌套 Image 实现左边长图
                    child: Image.network(
                        "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
                        fit: BoxFit.cover,
                        height: 100),
                  )),
              SizedBox(width: 10), //高度为 10 的间距
              Expanded(
                flex: 1,
                child: Container( //Container 嵌套 ListView 实现右边上下两张自适应图
                  height: 100,
                  child: ListView(
                    children: [
                      Image.network(
                          "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
                          fit: BoxFit.cover,
                          height: 45),
                      SizedBox(height: 10), //高度为 10 的间距
                      Image.network(
                          "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
                          fit: BoxFit.cover,
                          height: 45),
                    ],
                  ),
                ),
              )
            ],
          ),
          Divider(), //横线
          Stack( // Stack + Align 实现定位布局
            children: [
              Align(
                  alignment: Alignment.topLeft,
                  child: Image.network("https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
                      width: 70,
                      height: 70,
                      fit: BoxFit.cover)
              ),
              Align(
                  alignment: Alignment.topCenter,
                  child: Image.network("https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
                      width: 70,
                      height: 70,
                      fit: BoxFit.cover)
              ),
              Align(
                  alignment: Alignment.topRight,
                  child: Image.network("https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
                      width: 70,
                      height: 70,
                      fit: BoxFit.cover)
              )
            ],
          ),
          Divider(), //横线
          ListTile( // ListTile 实现 item
            leading: ClipOval( //圆形图片
              child: Image.network(
                "https://img.lianzhixiu.com/uploads/210106/37-21010609363aS.jpg",
                width: 50,
                height: 50,
                fit: BoxFit.cover,
              ),
            ),
            title: Text(
              "你好,我是刘亦菲",//标题
              style: TextStyle(
                  color: Colors.green,
                  fontWeight: FontWeight.bold
              )
            ),
            subtitle: Text(
                "很高兴认识你",//副标题
                style: TextStyle(
                  color: Colors.orange,
                )
            ),
          )
        ],
      ),
    );
  }
}

六、总结

本文重点内容:

1、采用 效果 -> Widget 介绍 -> 代码实现的方式对 Image,ListView,GridView,Stack 进行了介绍

2、在介绍上面 Widget 的过程中,我们又穿插了其它一些 Widget 的讲解:ClipOval,ListTile,Expanded,SizedBox,Divider,Align,Positioned,Padding

3、最后通过一个综合案例对介绍的 Widget 进行组合使用

好了,本篇文章到这里就结束了,希望能给你带来帮助 🤝

感谢你阅读这篇文章

下篇预告

下篇文章我会介绍 Flutter Button 相关 Widget,以及 Flutter 2.x Button 的变化

参考和推荐

Flutter 官方 API 文档

你的点赞,评论,是对我巨大的鼓励!

欢迎关注我的公众号: sweetying ,文章更新可第一时间收到

如果有问题,公众号内有加我微信的入口,在技术学习、个人成长的道路上,我们一起前进!