【2025版 OpenHarmony】GitCode 口袋工具:Flutter + pull_to_refresh 组件封装与分页加载实现
本文介绍了GitCode口袋工具项目的功能更新,主要包括新增的自定义仓库卡片组件(RepositoryCard)和用户卡片组件(UserCard),以及对应的分页列表页面。这些组件采用Material Design 3风格设计,支持下拉刷新、上拉加载功能,并实现了完善的分页管理逻辑。文章详细说明了组件的实现方法、技术架构(基于Flutter框架)、使用指南以及常见问题解决方案。项目通过封装可复用的
一、项目概述
本次更新为 GitCode 口袋工具项目添加了以下核心功能:
-
自定义仓库列表卡片组件 - 封装了美观的仓库信息展示卡片
-

-
自定义用户列表卡片组件 - 封装了美观的用户信息展示卡片
-

-
下拉刷新功能 - 支持下拉手势刷新数据
-

-
上拉加载更多 - 支持上拉手势加载更多数据
-

-
数据分页管理 - 完整的分页加载逻辑实现(支持仓库和用户)
这些功能提升了用户体验,使应用能够高效地展示和浏览大量仓库和用户数据。
二、功能特性
2.1 核心功能
1. 自定义仓库卡片组件 (RepositoryCard)
-
📦 信息展示:仓库名称、描述、编程语言、Star 数、Fork 数、更新时间
-
🎨 视觉设计:Material Design 3 风格,圆角卡片,支持点击反馈
-
🌈 语言颜色:根据编程语言自动显示不同颜色标识
-
📊 数字格式化:自动将大数字格式化为易读形式(如 1.5k)
-
🔒 私有标识:区分公开和私有仓库的图标显示
2. 分页列表页面 (RepositoryListPage)
-
🔄 下拉刷新:支持下拉手势刷新当前数据
-
⬆️ 上拉加载:滚动到底部自动加载更多数据
-
📄 分页管理:自动管理页码,每页加载 20 条数据
-
⚠️ 错误处理:完善的错误提示和重试机制
-
🎯 状态管理:加载中、空状态、错误状态的完整处理
3. 自定义用户卡片组件 (UserCard)
-
👤 信息展示:用户头像、名称、登录名、注册时间、主页地址
-
🎨 视觉设计:Material Design 3 风格,圆角卡片,支持点击反馈
-
📅 日期格式化:自动将 ISO 日期格式化为易读形式(YYYY-MM-DD)
-
🔗 链接展示:用户主页地址以蓝色链接形式展示
-
📐 固定高度:卡片高度固定为 150px,确保列表整齐
4. 用户分页列表页面 (UserListPage)
-
🔄 下拉刷新:支持下拉手势刷新当前数据
-
⬆️ 上拉加载:滚动到底部自动加载更多数据
-
📄 分页管理:自动管理页码,每页加载 20 条数据
-
⚠️ 错误处理:完善的错误提示和重试机制
-
🎯 状态管理:加载中、空状态、错误状态的完整处理
5. 主页面集成
-
🔍 搜索结果预览:使用新卡片组件展示搜索结果(仓库和用户)
-
🔗 快速跳转:一键跳转到完整列表页面(支持仓库和用户)
-
🎨 统一风格:保持整体 UI 风格一致性
2.2 技术架构
技术栈
-
Flutter SDK: ^3.6.2
-
pull_to_refresh: ^2.0.0 - 下拉刷新和上拉加载库
-
dio: ^5.7.0 - HTTP 请求库
-
Material Design 3: 现代化 UI 设计
架构设计
┌─────────────────────────────────────────┐
│ GitCodePocketToolPage │
│ (主页面) │
│ ┌───────────────────────────────────┐ │
│ │ 搜索结果预览 │ │
│ │ ├─ RepositoryCard (仓库卡片) │ │
│ │ └─ UserCard (用户卡片) │ │
│ │ ↓ 点击查看全部 │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
↓ ↓
┌───────────────────┐ ┌─────────────────────┐
│ RepositoryListPage│ │ UserListPage │
│ (仓库列表页) │ │ (用户列表页) │
│ ┌──────────────┐ │ │ ┌───────────────┐ │
│ │SmartRefresher│ │ │ │SmartRefresher │ │
│ │ ┌──────────┐ │ │ │ │ ┌────────┐ │ │
│ │ │ListView │ │ │ │ │ │ListView│ │ │
│ │ │Repository│ │ │ │ │ │UserCard│ │ │
│ │ └──────────┘ │ │ │ │ └────────┘ │ │
│ └──────────────┘ │ │ └───────────────┘ │
└───────────────────┘ └─────────────────────┘
↓ ↓
┌─────────────────────────────────────────┐
│ GitCodeApiClient (API层) │
│ ┌───────────────────────────────────┐ │
│ │ searchRepositories(page, perPage) │ │
│ │ searchUsers(page, perPage) │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
2.3 依赖说明
新增依赖
在 pubspec.yaml 中添加了以下依赖:
dependencies:
pull_to_refresh: ^2.0.0
依赖安装
运行以下命令安装依赖:
flutter pub get
依赖说明
pull_to_refresh 是一个功能强大的 Flutter 下拉刷新和上拉加载库,提供了:
-
下拉刷新功能
-
上拉加载更多功能
-
自定义刷新头部和底部
-
多种刷新样式支持
-
完善的加载状态管理
2.4 代码实现详解
1. 自定义仓库卡片组件
文件路径: lib/widgets/repository_card.dart
组件结构
class RepositoryCard extends StatelessWidget {
const RepositoryCard({
super.key,
required this.repository,
this.onTap,
});
final GitCodeRepository repository;
final VoidCallback? onTap;
}
核心功能实现
1.1 卡片布局
组件使用 Card + InkWell 实现可点击的卡片效果:
Card(
elevation: 2,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(...),
),
)
设计要点:
-
elevation: 2- 适中的阴影效果 -
borderRadius: 12- 圆角设计,符合 Material Design 3 -
InkWell- 提供点击波纹效果
1.2 仓库信息展示
仓库名称和图标:
Row(
children: [
Icon(
repository.isPrivate == true
? Icons.lock_outline
: Icons.folder_outlined,
color: theme.colorScheme.primary,
size: 20,
),
Expanded(
child: Text(
repository.fullName,
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
)
描述信息:
if (repository.description?.isNotEmpty == true)
Text(
repository.description!,
style: theme.textTheme.bodyMedium?.copyWith(
color: Colors.grey[700],
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
1.3 统计信息展示
使用 _buildStatItem 方法构建统计项:
Widget _buildStatItem({
required IconData icon,
required String label,
Color? color,
}) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 16, color: color ?? Colors.grey[600]),
const SizedBox(width: 4),
Text(
label,
style: TextStyle(
fontSize: 12,
color: color ?? Colors.grey[700],
),
),
],
);
}
统计项包括:
-
编程语言(带颜色标识)
-
Star 数量
-
Fork 数量
1.4 语言颜色映射
Color _getLanguageColor(String language) {
final colors = <String, Color>{
'Dart': Colors.blue,
'Java': Colors.orange,
'JavaScript': Colors.yellow[700]!,
'Python': Colors.blue[300]!,
'Go': Colors.cyan,
'TypeScript': Colors.blue[800]!,
'C++': Colors.pink,
'C': Colors.grey[800]!,
'Swift': Colors.orange[300]!,
'Kotlin': Colors.purple,
'Rust': Colors.orange[900]!,
};
return colors[language] ?? Colors.grey[600]!;
}
支持的编程语言颜色:
-
为常见编程语言设置了专属颜色
-
未匹配的语言使用默认灰色
1.5 数字格式化
String _formatNumber(int number) {
if (number >= 1000) {
return '${(number / 1000).toStringAsFixed(1)}k';
}
return number.toString();
}
格式化规则:
-
小于 1000:直接显示数字
-
大于等于 1000:转换为 k 单位(如 1500 → 1.5k)
2. 仓库分页列表页面
文件路径: lib/pages/repository_list_page.dart
页面结构
class RepositoryListPage extends StatefulWidget {
const RepositoryListPage({
super.key,
required this.keyword,
required this.token,
});
final String keyword;
final String token;
}
状态管理
class _RepositoryListPageState extends State<RepositoryListPage> {
final RefreshController _refreshController = RefreshController(
initialRefresh: false,
);
final GitCodeApiClient _client = GitCodeApiClient();
List<GitCodeRepository> _repositories = [];
int _currentPage = 1;
final int _perPage = 20;
bool _hasMore = true;
String? _errorMessage;
bool _isLoading = false;
}
状态变量说明:
-
_refreshController: 刷新控制器,管理下拉刷新和上拉加载状态 -
_repositories: 仓库列表数据 -
_currentPage: 当前页码 -
_perPage: 每页数据量(固定为 20) -
_hasMore: 是否还有更多数据 -
_errorMessage: 错误信息 -
_isLoading: 加载状态
核心方法实现
2.1 数据加载方法
Future<void> _loadRepositories({bool refresh = false}) async {
if (_isLoading) return;
if (refresh) {
_currentPage = 1;
_hasMore = true;
_repositories.clear();
}
if (!_hasMore) {
_refreshController.loadNoData();
return;
}
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
final repos = await _client.searchRepositories(
keyword: widget.keyword,
personalToken: widget.token,
perPage: _perPage,
page: _currentPage,
);
setState(() {
if (refresh) {
_repositories = repos;
} else {
_repositories.addAll(repos);
}
// 判断是否还有更多数据
_hasMore = repos.length >= _perPage;
_currentPage++;
_errorMessage = null;
_isLoading = false;
});
// 更新刷新控制器状态
if (refresh) {
_refreshController.refreshCompleted();
} else {
if (_hasMore) {
_refreshController.loadComplete();
} else {
_refreshController.loadNoData();
}
}
} on GitCodeApiException catch (e) {
// 错误处理...
}
}
方法逻辑:
-
防重复加载:如果正在加载,直接返回
-
刷新模式:重置页码和数据列表
-
数据加载:调用 API 获取数据
-
数据合并:
-
刷新模式:替换所有数据
-
加载更多:追加到现有数据
-
-
状态更新:更新 UI 和刷新控制器状态
2.2 刷新和加载回调
/// 下拉刷新
void _onRefresh() {
_loadRepositories(refresh: true);
}
/// 上拉加载
void _onLoading() {
_loadRepositories(refresh: false);
}
2.3 UI 构建
SmartRefresher 配置:
SmartRefresher(
controller: _refreshController,
enablePullDown: true,
enablePullUp: _hasMore,
header: const ClassicHeader(
refreshingText: '刷新中...',
completeText: '刷新完成',
idleText: '下拉刷新',
releaseText: '释放刷新',
),
footer: ClassicFooter(
loadingText: '加载中...',
noDataText: '没有更多数据了',
idleText: '上拉加载更多',
canLoadingText: '释放加载',
),
onRefresh: _onRefresh,
onLoading: _onLoading,
child: ListView.builder(...),
)
配置说明:
-
enablePullDown: true- 启用下拉刷新 -
enablePullUp: _hasMore- 根据是否有更多数据启用上拉加载 -
header- 自定义刷新头部提示文字 -
footer- 自定义加载底部提示文字
列表构建:
ListView.builder(
itemCount: _repositories.length,
padding: const EdgeInsets.symmetric(vertical: 8),
itemBuilder: (context, index) {
return RepositoryCard(
repository: _repositories[index],
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('点击了: ${_repositories[index].fullName}'),
duration: const Duration(seconds: 2),
),
);
},
);
},
)
2.4 错误处理
错误状态展示:
_errorMessage != null && _repositories.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, size: 64, color: Colors.red[300]),
const SizedBox(height: 16),
Text(_errorMessage!, style: TextStyle(color: Colors.red[700])),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => _onRefresh(),
child: const Text('重试'),
),
],
),
)
空状态展示:
_repositories.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.search_off, size: 64, color: Colors.grey[400]),
const SizedBox(height: 16),
Text('暂无数据', style: TextStyle(color: Colors.grey[600])),
],
),
)
3. 自定义用户卡片组件
文件路径: lib/widgets/user_card.dart
组件结构
class UserCard extends StatelessWidget {
const UserCard({
super.key,
required this.user,
this.onTap,
this.height,
});
final GitCodeSearchUser user;
final VoidCallback? onTap;
final double? height;
}
核心功能实现
3.1 卡片布局
组件使用 Card + InkWell + Row 布局,左侧显示头像,右侧显示用户信息:
Card(
elevation: 2,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 左侧头像
CircleAvatar(...),
// 右侧用户信息
Expanded(
child: Column(...),
),
],
),
),
),
)
3.2 用户信息展示
头像显示:
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(user.avatarUrl),
onBackgroundImageError: (_, __) {},
backgroundColor: theme.colorScheme.surfaceVariant,
child: user.avatarUrl.isEmpty
? Icon(Icons.person, ...)
: null,
)
用户名称:
Text(
displayName, // user.name ?? user.login
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 16,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
登录名:
Row(
children: [
Icon(Icons.person_outline, size: 14),
Text(
user.login,
style: theme.textTheme.bodyMedium?.copyWith(
fontSize: 13,
),
),
],
)
注册时间:
Row(
children: [
Icon(Icons.calendar_today, size: 13),
Text(
'注册于 ${_formatDate(user.createdAt!)}',
style: theme.textTheme.bodySmall?.copyWith(
fontSize: 12,
),
),
],
)
主页地址:
Row(
children: [
Icon(Icons.link, size: 13),
Text(
user.htmlUrl!,
style: theme.textTheme.bodySmall?.copyWith(
color: Colors.blue[600],
fontSize: 12,
),
),
],
)
3.3 日期格式化
String _formatDate(String dateString) {
try {
final date = DateTime.parse(dateString);
return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
} catch (e) {
return dateString.length > 10 ? dateString.substring(0, 10) : dateString;
}
}
格式化规则:
-
尝试解析 ISO 8601 格式日期
-
格式化为 YYYY-MM-DD 格式
-
解析失败时返回原始字符串的前10个字符
3.4 固定高度设计
卡片使用固定高度设计,确保列表整齐:
// 固定每行的高度常量
static const double _avatarSize = 40.0;
static const double _titleRowHeight = 20.0;
static const double _loginRowHeight = 18.0;
static const double _infoRowHeight = 18.0;
static const double _urlRowHeight = 18.0;
static const double _spacing = 6.0;
static const double _padding = 12.0;
// 计算总高度
final calculatedHeight = _padding * 2 +
_avatarSize +
_spacing +
_titleRowHeight +
_spacing +
_loginRowHeight +
_spacing +
_infoRowHeight +
_spacing +
_urlRowHeight +
8.0; // 余量
4. 用户分页列表页面
文件路径: lib/pages/user_list_page.dart
页面结构
class UserListPage extends StatefulWidget {
const UserListPage({
super.key,
required this.keyword,
required this.token,
});
final String keyword;
final String token;
}
状态管理
class _UserListPageState extends State<UserListPage> {
final RefreshController _refreshController = RefreshController(
initialRefresh: false,
);
final GitCodeApiClient _client = GitCodeApiClient();
List<GitCodeSearchUser> _users = [];
int _currentPage = 1;
final int _perPage = 20;
bool _hasMore = true;
String? _errorMessage;
bool _isLoading = false;
}
状态变量说明:
-
_refreshController: 刷新控制器,管理下拉刷新和上拉加载状态 -
_users: 用户列表数据 -
_currentPage: 当前页码 -
_perPage: 每页数据量(固定为 20) -
_hasMore: 是否还有更多数据 -
_errorMessage: 错误信息 -
_isLoading: 加载状态
核心方法实现
4.1 数据加载方法
Future<void> _loadUsers({bool refresh = false}) async {
if (_isLoading) return;
if (refresh) {
_currentPage = 1;
_hasMore = true;
_users.clear();
}
if (!_hasMore) {
_refreshController.loadNoData();
return;
}
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
final users = await _client.searchUsers(
keyword: widget.keyword,
personalToken: widget.token,
perPage: _perPage,
page: _currentPage,
);
setState(() {
if (refresh) {
_users = users;
} else {
_users.addAll(users);
}
_hasMore = users.length >= _perPage;
_currentPage++;
_errorMessage = null;
_isLoading = false;
});
// 更新刷新控制器状态
if (refresh) {
_refreshController.refreshCompleted();
} else {
if (_hasMore) {
_refreshController.loadComplete();
} else {
_refreshController.loadNoData();
}
}
} on GitCodeApiException catch (e) {
// 错误处理...
}
}
方法逻辑:
-
防重复加载:如果正在加载,直接返回
-
刷新模式:重置页码和数据列表
-
数据加载:调用 API 获取用户数据
-
数据合并:
-
刷新模式:替换所有数据
-
加载更多:追加到现有数据
-
-
状态更新:更新 UI 和刷新控制器状态
4.2 UI 构建
列表构建:
ListView.builder(
itemCount: _users.length,
padding: const EdgeInsets.symmetric(vertical: 8),
itemBuilder: (context, index) {
return UserCard(
user: _users[index],
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('点击了用户: ${_users[index].name ?? _users[index].login}'),
duration: const Duration(seconds: 2),
),
);
},
);
},
)
用户列表页面的实现与仓库列表页面类似,都使用 SmartRefresher 实现下拉刷新和上拉加载功能。
5. 主页面集成
文件路径: lib/main.dart
导入新组件
import 'pages/repository_list_page.dart';
import 'pages/user_list_page.dart';
import 'widgets/repository_card.dart';
import 'widgets/user_card.dart';
修改仓库结果展示
原实现(使用 _RepoTile):
return Column(
children: _repoResults.map(_RepoTile.new).toList(),
);
新实现(使用 RepositoryCard + 跳转按钮):
return Column(
children: [
// 使用新的自定义仓库卡片组件
..._repoResults.map(
(repo) => RepositoryCard(
repository: repo,
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('点击了: ${repo.fullName}'),
duration: const Duration(seconds: 2),
),
);
},
),
),
const SizedBox(height: 16),
// 添加查看全部按钮,跳转到带分页的列表页
FilledButton.icon(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RepositoryListPage(
keyword: _keywordController.text,
token: _tokenController.text.trim(),
),
),
);
},
icon: const Icon(Icons.list),
label: const Text('查看全部并加载更多'),
),
],
);
修改用户结果展示
原实现(使用 _UserTile):
return Column(
children: _userResults.map(_UserTile.new).toList(),
);
新实现(使用 UserCard + 跳转按钮):
return Column(
children: [
// 使用新的自定义用户卡片组件
..._userResults.map(
(user) => UserCard(
user: user,
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('点击了用户: ${user.name ?? user.login}'),
duration: const Duration(seconds: 2),
),
);
},
),
),
const SizedBox(height: 16),
// 添加查看全部按钮,跳转到带分页的用户列表页
FilledButton.icon(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserListPage(
keyword: _keywordController.text,
token: _tokenController.text.trim(),
),
),
);
},
icon: const Icon(Icons.list),
label: const Text('查看全部并加载更多'),
),
],
);
改进点:
-
使用新的
RepositoryCard和UserCard组件,视觉效果更好 -
添加跳转按钮,可以查看完整列表(支持仓库和用户)
-
保持原有功能不变,向后兼容
三、使用指南
3.1 环境准备
3.2 下载仓库压缩包
仓库地址:
3.3 配置访问令牌
配置令牌名称和到期时间,之后向下滑找到新建访问令牌按钮,点击此按钮新建:
注意重要:新建成功后,一定要复制好这个访问令牌,并且保存好,不要让别人知道!

3.4 解压项目并打开
打开之后目录如图所示:

点击app_config.dart文件,并将你的访问令牌复制到此位置:
注意:这只是调式项目仅供学习参考,正式环境下,需要将访问令牌隐式配置到本地,不在其中显示。

3.5 开始启动项目
替换成功后,在DevEco Studio中编译运行此项目,点击右上角绿色运行按钮,启动过程中耐心等待。注意,虚拟机启动需要保证虚拟机连接上网络:

如图所示启动成功:

3.6 项目展示
搜索用户:


下拉实现刷新,下滑会自动刷新

搜索仓库:


下拉实现刷新,下滑会自动刷新

3.7 代码使用示例
使用 RepositoryCard 组件
RepositoryCard(
repository: gitCodeRepository,
onTap: () {
// 处理点击事件
print('点击了仓库: ${gitCodeRepository.fullName}');
},
)
使用 UserCard 组件
UserCard(
user: gitCodeUser,
onTap: () {
// 处理点击事件
print('点击了用户: ${gitCodeUser.name ?? gitCodeUser.login}');
},
)
跳转到仓库列表页面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RepositoryListPage(
keyword: 'flutter',
token: 'your_access_token',
),
),
);
跳转到用户列表页面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserListPage(
keyword: 'john',
token: 'your_access_token',
),
),
);
四、文件结构
新增文件
lib/
├── widgets/
│ ├── repository_card.dart # 自定义仓库卡片组件
│ └── user_card.dart # 自定义用户卡片组件
└── pages/
├── repository_list_page.dart # 仓库分页列表页面
└── user_list_page.dart # 用户分页列表页面
修改文件
lib/
└── main.dart # 主页面(集成新组件)
pubspec.yaml # 添加 pull_to_refresh 依赖
完整文件结构
gitcode_pocket_tool/
├── lib/
│ ├── core/
│ │ ├── app_config.dart
│ │ └── gitcode_api.dart
│ ├── pages/
│ │ ├── repository_list_page.dart # 新增
│ │ └── user_list_page.dart # 新增
│ ├── widgets/
│ │ ├── repository_card.dart # 新增
│ │ └── user_card.dart # 新增
│ └── main.dart # 修改
├── pubspec.yaml # 修改
└── docs/
└── 组件封装与分页加载实现文档.md # 本文档
五、API 说明
GitCodeApiClient.searchUsers
方法签名:
Future<List<GitCodeSearchUser>> searchUsers({
required String keyword,
required String personalToken,
int perPage = 10,
int page = 1,
})
参数说明:
-
keyword: 搜索关键字(必需) -
personalToken: 个人访问令牌(必需) -
perPage: 每页数据量(默认 10,最大 50) -
page: 页码(默认 1,最大 100)
返回值:
-
List<GitCodeSearchUser>: 用户列表
使用示例:
final users = await _client.searchUsers(
keyword: 'john',
personalToken: 'your_token',
perPage: 20,
page: 1,
);
GitCodeApiClient.searchRepositories
方法签名:
Future<List<GitCodeRepository>> searchRepositories({
required String keyword,
required String personalToken,
String? language,
String? sort,
String? order,
int perPage = 10,
int page = 1,
})
参数说明:
-
keyword: 搜索关键字(必需) -
personalToken: 个人访问令牌(必需) -
language: 编程语言过滤(可选) -
sort: 排序方式(可选) -
order: 排序顺序(可选) -
perPage: 每页数据量(默认 10,最大 50) -
page: 页码(默认 1,最大 100)
返回值:
-
List<GitCodeRepository>: 仓库列表
使用示例:
final repos = await _client.searchRepositories(
keyword: 'flutter',
personalToken: 'your_token',
perPage: 20,
page: 1,
);
六、最佳实践
1. 组件封装原则
-
✅ 单一职责:每个组件只负责一个功能
-
✅ 可复用性:组件设计时考虑复用场景
-
✅ 参数化:通过参数控制组件行为
-
✅ 文档完善:添加清晰的注释和文档
2. 状态管理
-
✅ 状态集中:相关状态集中管理
-
✅ 状态同步:确保 UI 状态与数据状态同步
-
✅ 错误处理:完善的错误处理和用户提示
3. 性能优化
-
✅ 懒加载:使用 ListView.builder 实现懒加载
-
✅ 分页加载:避免一次性加载大量数据
-
✅ 防重复请求:添加加载状态检查
4. 用户体验
-
✅ 加载提示:清晰的加载状态提示
-
✅ 错误提示:友好的错误信息和重试机制
-
✅ 空状态:优雅的空状态展示
-
✅ 交互反馈:点击、刷新等操作的即时反馈
七、常见问题
Q1: 下拉刷新不生效?
可能原因:
-
RefreshController未正确初始化 -
enablePullDown未设置为true -
刷新回调方法未正确实现
解决方案:
// 确保控制器正确初始化
final RefreshController _refreshController = RefreshController(
initialRefresh: false,
);
// 确保启用下拉刷新
SmartRefresher(
enablePullDown: true,
onRefresh: _onRefresh,
// ...
)
// 确保刷新完成后调用
_refreshController.refreshCompleted();
Q2: 上拉加载不触发?
可能原因:
-
enablePullUp设置为false -
数据未达到触发加载的阈值
-
_hasMore状态不正确
解决方案:
// 根据是否有更多数据启用上拉加载
SmartRefresher(
enablePullUp: _hasMore,
onLoading: _onLoading,
// ...
)
// 确保正确判断是否还有更多数据
_hasMore = repos.length >= _perPage;
Q3: 分页数据重复?
可能原因:
-
刷新时未重置页码
-
数据追加逻辑错误
解决方案:
if (refresh) {
_currentPage = 1; // 重置页码
_repositories.clear(); // 清空数据
_repositories = repos; // 替换数据
} else {
_repositories.addAll(repos); // 追加数据
}
Q4: 如何自定义卡片样式?
解决方案: 修改 RepositoryCard 组件的样式参数:
Card(
elevation: 2, // 修改阴影
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), // 修改边距
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), // 修改圆角
),
// ...
)
Q5: 如何修改每页加载数量?
解决方案: 修改 _perPage 常量:
final int _perPage = 20; // 修改为你需要的数量(最大 50)
八、总结
本次更新成功实现了:
-
✅ 自定义仓库卡片组件 - 美观、可复用的 UI 组件
-
✅ 自定义用户卡片组件 - 美观、可复用的 UI 组件
-
✅ 仓库分页列表页面 - 完整的仓库列表浏览功能
-
✅ 用户分页列表页面 - 完整的用户列表浏览功能
-
✅ 下拉刷新功能 - 流畅的刷新体验(支持仓库和用户)
-
✅ 上拉加载更多 - 自动加载分页数据(支持仓库和用户)
-
✅ 完整的分页管理 - 可靠的数据加载逻辑
-
✅ 完善的错误处理 - 友好的用户提示
这些功能大大提升了应用的用户体验,使数据浏览更加高效和流畅。无论是搜索仓库还是搜索用户,都能享受到一致且流畅的浏览体验。
九、参考资料
文档版本: 2.0.0 最后更新: 2024年 维护者: GitCode 口袋工具开发团队
十、更新日志
v2.0.0 (最新)
-
✨ 新增用户卡片组件 (
UserCard) -
✨ 新增用户分页列表页面 (
UserListPage) -
✨ 主页面支持用户搜索和列表跳转
-
📝 更新文档,添加用户相关功能说明
v1.0.0
-
✨ 新增仓库卡片组件 (
RepositoryCard) -
✨ 新增仓库分页列表页面 (
RepositoryListPage) -
✨ 主页面支持仓库搜索和列表跳转
-
📝 初始文档版本
更多推荐




所有评论(0)