开源鸿蒙跨平台开发训练营--GitCode口袋工具(四)
Navigator 是 flutter 中页面导航的核心组件,基于栈结构。通过push入栈打开新的页面。通过pop弹出当前页面,从而返回上一个页面。Navigator 不但能管理页面之间的导航逻辑,还可以处理页面之间的参数传递、页面返回值处理、以及路由动画等功能。
今天的内容是去实现仓库详情页,即在仓库列表页面,点击某个仓库后,展示其详情页面。不过为了实现该功能,我们需要了解一些前置知识。
一、页面导航
在 flutter 中,我们想要从一个页面跳转到另一个页面,可以借助Navigator来实现界面之间的跳转。
1. Navigator 介绍
Navigator 是 flutter 中页面导航的核心组件,基于栈结构。通过push入栈打开新的页面。通过pop弹出当前页面,从而返回上一个页面。
Navigator 不但能管理页面之间的导航逻辑,还可以处理页面之间的参数传递、页面返回值处理、以及路由动画等功能。
2. Navigator 核心方法
Navigator 的导航分为基本导航方式和命名路由方式,由于我们没有跨模块,只在当前模块跳转界面,所以只需要使用基本导航即可。
// 打开页面
Navigator.push(context, MaterialPageRoute(builder: (context) => NewScreen()));
// 关闭当前页面
Navigator.pop(context);
// 关闭当前页面并返回数据
Navigator.pop(context, "返回的数据");
// 使用替换的方式打开新页面
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => NewScreen()));
// 清空当前栈中的页面,再打开新页面
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => NewScreen()), (route) => false);
在跳转页面时,还有一个重要的功能就是传递参数。
// 传递参数
Navigator.push(context,
MaterialPageRoute(builder: (context) => NewScreen('要传递的参数'))
);
// 接收方
class NewScreen extends StatefulWidget {
final XXX param;// 接受参数
const NewScreen({Key? key, required this.param}) : super(key: key);
@override
State<NewScreen> createState() => _NewScreenState();
}
我们编写一个page/repo/RepoDetailTestScreen.dart页面,内容非常简单,就是展示接受传递的参数,然后显示在界面上。
import 'package:flutter/material.dart';
class RepoDetailTestScreen extends StatefulWidget {
final String param;// 接受一个 String 类型的参数
const RepoDetailTestScreen({super.key, required this.param});
@override
State<RepoDetailTestScreen> createState() => _RepoDetailTestScreenState();
}
class _RepoDetailTestScreenState extends State<RepoDetailTestScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('仓库详情测试'),
),
body: Center(
child: Text('传入的参数: ${widget.param}'),
),
);
}
}
然后使用我们的测试页面,把 Button 点击事件中的代码删除,替换成 Navigator。
const param = "Hello Test Page";
Navigator.push(context, MaterialPageRoute(builder: (context) => RepoDetailTestScreen(param: param)));

如图所示,可以界面可以正常打开,而且参数接受正常。
二、编写仓库详情页
仓库详情页稍微比较复杂,这一章我们先实现上半部分的功能。
1. 仓库详细信息展示
我们在仓库列表页,点击某个 item 后,跳转到仓库详情页,并且把当前点击的仓库实体类传递到仓库详情页,并且展示仓库的一些信息。

然后我们在仓库详情页,接受这个数据。

从上到下,我们分别展示项目名称,项目描述,项目语言,项目默认分支,项目所有者信息,项目命名空间 path,以及项目对应的 start、fork、issues 数量。
由于手机屏幕空间有限,我们设计一个可折叠项,可以将 start、fork、issues 进行折叠。如下图所示,分别是折叠和打开的截图。而且为了提高用户体验,我们使用动画来折叠和打开。
2. 使用动画
我们借助 SizeTransition 内置组件来实现动画效果,该组件可以通过axis属性来设置大小改变的方向,例如:设置Axis.vertical表示垂直方向。使用sizeFactor设置动画对象。child属性表示子组件,即动画要控制的组件。axisAlignment表示动画起始方向,-1.0 在垂直方向表示从顶部开始,从上往下展开。
// 折叠相关状态,控制当前状态是打开还是折叠
bool _isStatsExpanded = true;
// 动画控制器,控制动画启动和暂停
late AnimationController _expandController;
// 动画实例对象
late Animation<double> _expandAnimation;
// 初始化动画控制器
_expandController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
value: _isStatsExpanded ? 1.0 : 0.0,
);
// 初始化动画对象,使用 Curves.easeInOut 效果
_expandAnimation = _expandController.drive(CurveTween(curve: Curves.easeInOut));
// 使用 SizeTransition 动画组件,根据动画改变组件大小。
SizeTransition(
axis: Axis.vertical,
// 折叠时从下往上隐藏,打开时从上往下显示
axisAlignment: -1.0,
sizeFactor: _expandAnimation,
child: Padding(
padding: const EdgeInsets.only(top: 16),
child: Column(
children: [
// 第一行:Watch、Star
Row(
children: [
Expanded(
child: _buildStatItemWithBorder('Star', repo.stargazersCount),
),
],
),
// 第二行:Fork、Pull Requests
Padding(
padding: const EdgeInsets.only(top: 12),
child: Row(
children: [
Expanded(
child: _buildStatItemWithBorder('Fork', repo.forksCount),
),
const SizedBox(width: 12),
Expanded(
child: _buildStatItemWithBorder('Issues', repo.openIssuesCount),
),
],
),
),
],
),
),
),
此时如果你的代码可能有报错,如截图所示:


这个是因为参数需要一个TickerProvider实例对象,而我们当前类不是这个类型。所以我们需要让我们的类集成TickerProvider接口。但是由于我们的类已经extends State,所以需要使用 with 来实现多继承。
class _RepoDetailScreenState extends State<RepoDetailScreen> with TickerProviderStateMixin
最终实现效果如下:


三、报错问题

如上图所示,报错是因为动画的组件使用错误导致的问题。
1. TickerProvider
Ticker对象是系统提供的动画组件。而 TickerProvider 是一个接口,负责管理Ticker实例对象,他可以自动管理 Ticker 的生命周期,确保动画在组件可见时执行,防止资源浪费。
2. SingleTickerProviderStateMixin 和 TickerProviderStateMixin
SingleTickerProviderStateMixin 可以为 State 类提供创建单个Ticker的能力。适用于页面只需要一个动画控制器的情况。
TickerProviderStateMixin 可以为 State 类提供创建多个Ticker的能力。如果页面中需要多个动画控制器,则建议使用这个。
我们的页面只有一个折叠和打开的动画,所以刚开始我使用的是 SingleTickerProviderStateMixin。运行后就会出现上图的错误。经过查询,出现改问题是因为我们项目里虽然只有折叠和打开一个动画,但是还有一个 TabController,他在切换页面的时候内部也会执行动画,所以 TabController + 折叠、打开动画,就需要使用 TickerProviderStateMixin 了。
更多推荐



所有评论(0)