第五章:Scrollable Widgets(二) -- ListView

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

ListView是UI中最常见的一种组件之一,它会线性的排列其中的子组件,并可以在水平或者垂直方向上进行滑动。
在这里插入图片描述
ListView有四种不同的构造方法,适用于不同的情况:

  1. 默认构造器,直接声明children列表,这将构建列表中的每个子元素,即使是那些不可见的子元素。适用于子元素比较少的情景。
  2. ListView.builder()使用一个 IndexedWidgetBuilder 进行构建,这种只会构建可见的子元素,如果子元素的数量很大的时候适用于这种方式。
  3. ListView.separated()使用两个 IndexedWidgetBuilders进行构建,itemBuilder
    seperatorBuilder,如果你想在子元素之间设置一下分隔线的话适合使用这种方式。
  4. ListView.custom(),顾名思义,自定义的方式来实现列表。

回到项目中,第一屏是 ExploreScreen,包含两个列表:

  • TodayRecipeListView,水平滑动的列表
  • FriendPostListView,垂直滑动的列表
    在这里插入图片描述

lib目录下创建一个screens文件夹创建explore_screen.dart,添加如下代码:

import 'package:flutter/material.dart';

import '../api/mock_fooderlich_service.dart';

class ExploreScreen extends StatelessWidget {
  //MockFooderlichService 模拟服务端的响应数据
  final mockService = MockFooderlichService();

  ExploreScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //占位后续继续开发
    // TODO 1: Add TodayRecipeListView FutureBuilder
    return const Center(
      child: Text('Explore Screen'),
    );
  }
}

回到home.dart中,定位到 TODO: Replace with ExploreScreen这里,替换为

ExploreScreen(),

这样就把我们刚才创建的ExploreScreen加入到第一屏中了,如果IDE没有自动导入这个类的话,你需要手动导入:

import 'screens/explore_screen.dart';

运行APP,现在效果如下:
在这里插入图片描述
回到 explore_screen.dart中,我们学习一下通过异步任务来更新UI。MockFooderlichService中包含了一个异步方法返回一个Future,定位到TODO 1: Add TodayRecipeListView FutureBuilder替换为如下代码:

	return FutureBuilder(
        //使用getExploreData()返回的future作为FutureBuilder的参数
        future: mockService.getExploreData(),
        //使用snapshot来查看Future的状态
        builder: (context, AsyncSnapshot<ExploreData> snapshot) {
          //如果Future已经完成,可以获取数据来更新UI
          if (snapshot.connectionState == ConnectionState.done) {
            final recipes = snapshot.data?.todayRecipes ?? [];
            // TODO: Replace this with TodayRecipeListView
            return Center(
                child: Container(
              child: const Text('Show TodayRecipeListView'),
            ));
          } else {
            //如果Future还没完成,则提示用户
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        });

运行后效果如下:
在这里插入图片描述

实现ListView

我们要先实现TodayRecipeListView,这是一个横向滑动的ListView。进入文件夹lib/components,创建today_recipe_list_view.dart,代码如下:

import 'package:flutter/material.dart';

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

class TodayRecipeListView extends StatelessWidget {
  //展示的数据
  final List<ExploreRecipe> recipes;

  const TodayRecipeListView({
    Key? key,
    required this.recipes,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //添加一个padding
    return Padding(
      padding: const EdgeInsets.only(
        left: 16,
        right: 16,
        top: 16,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          //标题
          Text('Recipes of the Day " ',
              style: Theme.of(context).textTheme.headline1),
          const SizedBox(height: 16),
          //ListView的容器
          Container(
            height: 400,
            // TODO: Add ListView Here
            color: Colors.grey,
          ),
        ],
      ),
    );
  }
// TODO: Add buildCard() widget here
}

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

export 'today_recipe_list_view.dart';

这样我们导入components.dart之后就不用再导入这个类了。
打开explore_screen.dart文件,定位到 TODO: Replace this with TodayRecipeListView,替换为如下代码:

return TodayRecipeListView(recipes: recipes);

我们可以导入

import '../components/components.dart';

这样以后就不用重复导入components.dart里已经导入的文件了
运行APP,效果如下:
在这里插入图片描述

只有标题和背景,下面我们来实现ListView。

回到 today_recipe_list_view.dart 里,定位到 TODO: Add ListView Here ,把color这一行也替换掉:

		 //ListView的容器
          Container(
              height: 400,
              //颜色设置为透明
              color: Colors.transparent,
              //构造ListView
              child: ListView.separated(
                //滑动方向为横向
                scrollDirection: Axis.horizontal,
                //item数量
                itemCount: recipes.length,
                //构建item
                itemBuilder: (context, index) {
                  //通过buildCard()方法来构建item
                  final recipe = recipes[index];
                  return buildCard(recipe);
                },
                //构建分隔线
                separatorBuilder: (context, index) {
                  return const SizedBox(width: 16);
                },
              )),

这里构建了ListView,下面把 buildCard() 方法加上,定位到 TODO: Add buildCard() widget here,添加如下代码:

Widget buildCard(ExploreRecipe recipe) {
    if (recipe.cardType == RecipeCardType.card1) {
      return Card1(recipe: recipe);
    } else if (recipe.cardType == RecipeCardType.card2) {
      return Card2(recipe: recipe);
    } else if (recipe.cardType == RecipeCardType.card3) {
      return Card3(recipe: recipe);
    } else {
      throw Exception('This card doesn\'t exist yet');
    }
  }

运行APP,效果如下:
在这里插入图片描述

你也可以去main.dart中切换一下dark 模式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值