第五章:Scrollable Widgets

第五章:Scrollable Widgets,第1张

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 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 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 模式。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/584480.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存