Flutter-从入门到放弃(源码,目录,持续更新中)
ListView是UI中最常见的一种组件之一,它会线性的排列其中的子组件,并可以在水平或者垂直方向上进行滑动。
ListView有四种不同的构造方法,适用于不同的情况:
- 默认构造器,直接声明children列表,这将构建列表中的每个子元素,即使是那些不可见的子元素。
适用于子元素比较少的情景。
- ListView.builder()使用一个 IndexedWidgetBuilder 进行构建,这种只会构建可见的子元素,如果子元素的数量很大的时候适用于这种方式。
- ListView.separated()使用两个 IndexedWidgetBuilders进行构建,itemBuilder 和
seperatorBuilder,如果你想在子元素之间设置一下分隔线的话适合使用这种方式。 - 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(),
);
}
});
运行后效果如下:
我们要先实现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 模式。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)