第五章:Scrollable Widgets(三) -- ListView嵌套

Flutter-从入门到放弃(源码,目录,持续更新中)

前面讲了ListView的四种构造方式及对应的使用场景,今天我们继续来学习一下ListView的嵌套使用。

实现UI的两种方式

有两种方式来实现我们的UI布局,第一种是在Column中使用两个ListView来展示上半部分的菜谱和下半部分的发帖内容,就像下图一样:
在这里插入图片描述
可以看出来,上半部分横向滑动,可以很好的展示出来,但是下半部分垂直方向滑动,能够为每条帖子留下的空间非常小。

现在我们换一种ListView嵌套的方式来实现看看效果如何:
在这里插入图片描述
这种方式在一个ListView中嵌套了另外两个ListView,我们可以使用默认的构造器,直接声明两个子组件。这种实现方式的优点如下:

  1. 可滑动的区域更广
  2. 可以看到更多的发帖内容
  3. 可以在水平方向上滑动菜谱列表
  4. 当你向上滑动时,Flutter将监听到父ListView的滑动事件,菜谱列表和帖子都会向上滑动,可以有更多的空间来展示帖子。

这样看起来是不是更好呢,我们来试试吧。

ListView的嵌套使用

先打开explore_screen.dart,将build()方法的内容替换如下:

 @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        //使用getExploreData()返回的future作为FutureBuilder的参数
        future: mockService.getExploreData(),
        //使用snapshot来查看Future的状态
        builder: (context, AsyncSnapshot<ExploreData> snapshot) {
          //如果Future已经完成,可以获取数据来更新UI
          if (snapshot.connectionState == ConnectionState.done) {
            return ListView(
              //指定滑动方向
              scrollDirection: Axis.vertical,
              //声明子Widget
              children: [
                //上半部分的菜谱列表
                TodayRecipeListView(recipes: snapshot.data?.todayRecipes ?? []),
                //添加一个间距
                const SizedBox(height: 16),
                //TODO: Replace this with FriendPostListView
                Container(
                  height: 400,
                  color: Colors.green,
                )
              ],
            );
          } else {
            //如果Future还没完成,则提示用户
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        });
  }

可以看出变化主要是将原来的菜谱列表替换为一个父ListView,内部准备嵌套两个子ListView,当然,下半部分的ListView我们还没完成,实际效果如下:
在这里插入图片描述
上下滑动时可以为上半部分或者下半部分留出更多的空间,左右滑动时又可以很好的展示菜谱列表,效果非常的棒,这个效果的实现真的比Android简单多了。。。

实现发帖ListView

首先我们把列表中的item进行实现,然后再来完成整个列表。每个帖子的效果如下:

在这里插入图片描述
lib/components里创建 friend_post_tile.dart.,添加如下代码:

import 'package:flutter/material.dart';
import '../components/components.dart';
import '../models/models.dart';

class FriendPostTile extends StatelessWidget {
  final Post post;

  const FriendPostTile({
    Key? key,
    required this.post,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //1.创建一个Row Widget,它是一个水平布局的组件
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        //2.左边放置一个圆角图片
        CircleImage(
          imageProvider: AssetImage(post.profileImageUrl),
          imageRadius: 20,
        ),
        //3.添加一个间距
        const SizedBox(width: 16),
        //4.Expanded组件,让子组件填充剩余的空间
        Expanded(
          //5.Column组件,垂直方向的布局
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              //6.帖子的内容
              Text(post.comment),
              //7.发帖的时间
              Text(
                '${post.timestamp} mins ago',
                style: const TextStyle(fontWeight: FontWeight.w700),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

注意,我们这里没有限制组件的高度,它不会受到高度限制,将会把所有的内容展示出来。

打开components.dart,添加如下代码:

export 'friend_post_tile.dart';

现在我们可以来实现发帖列表了。
lib/components中创建 friend_post_list_view.dart,添加如下代码:

import 'package:flutter/material.dart';

import '../models/models.dart';
import 'friend_post_tile.dart';

class FriendPostListView extends StatelessWidget {
  //1.帖子的数据集合
  final List<Post> friendPosts;

  const FriendPostListView({
    Key? key,
    required this.friendPosts,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //2.设置左右的padding
    return Padding(
      padding: const EdgeInsets.only(
        left: 16,
        right: 16,
        top: 0,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          //4.设置了一个标题
          Text('Social Chefs ! ', style: Theme.of(context).textTheme.headline1),
          //5.标题和列表之间的间距
          const SizedBox(height: 16),
          //6.列表的具体实现
          ListView.separated(
            //7.设置primary为false,告诉系统这不是一个主ListView
            primary: false,
            //8.设置不滚动,让父ListView来处理滚动事件
            physics: const NeverScrollableScrollPhysics(),
            //9.设置为true时将创建一个固定长度的可滚动集合
            //设为false时会有一个an unbounded height 的错误
            shrinkWrap: true,
            scrollDirection: Axis.vertical,
            itemCount: friendPosts.length,
            itemBuilder: (context, index) {
              //实际的item
              final post = friendPosts[index];
              return FriendPostTile(post: post);
            },
            separatorBuilder: (context, index) {
              //item之间的间距
              return const SizedBox(height: 16);
            },
          ),
          const SizedBox(height: 16),
        ],
      ),
    );
  }
}

同样在 components.dart 中导入该类:

export 'friend_post_list_view.dart';

现在我们进入 explore_screen.dart,把TODO: Replace this with FriendPostListView 提示下的 Container 替换为:

				//下半部分的帖子列表
                FriendPostListView(
                    friendPosts: snapshot.data?.friendPosts ?? []),

运行APP,体验一下效果吧。
在这里插入图片描述
你也可以在 main.dart中切换为 dark 模式来体验一下:
在这里插入图片描述
ListView的嵌套使用就完成了,下一节我们将会学习GridView的使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值