

dart
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:ayidaojia/common/index.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'index.dart';
class TeamPage extends GetView<TeamController> {
const TeamPage({super.key});
// 头部背景图(放在 SliverAppBar 的 flexibleSpace 中)
Widget _buildHeaderBackground() {
return Stack(
children: [
// 背景图
Positioned(
left: 0,
right: 0,
top: 0,
child: ImgWidget(
path: 'assets/img/team1.png',
width: 750.w,
height: 496.w,
fit: BoxFit.cover,
),
),
// 自定义内容(可选)
Positioned(
left: 0,
right: 0,
bottom: 0,
child: <Widget>[
TextWidget.body('自定义顶部内容1', size: 32.sp, weight: FontWeight.w600,),
TextWidget.body('自定义顶部内容2', size: 32.sp, weight: FontWeight.w600,),
TextWidget.body('自定义顶部内容3', size: 32.sp, weight: FontWeight.w600,),
].toColumn(),
),
],
);
}
// 列表项
Widget _buildListItem(int index) {
return Container(
padding: EdgeInsets.symmetric(vertical: 20.w),
child: TextWidget.body(
'item = $index',
size: 30.sp,
color: Colors.black,
),
);
}
@override
Widget build(BuildContext context) {
// 状态栏高度
final double statusBarHeight = MediaQuery.of(context).padding.top;
// 导航栏高度
final double navBarHeight = 88.w;
// SliverAppBar 展开后的总高度(状态栏 + 导航栏 + 背景图高度)
final double expandedHeight = statusBarHeight + navBarHeight + 400.w;
return GetBuilder<TeamController>(
init: TeamController(),
id: "team",
builder: (_) {
return Scaffold(
backgroundColor: AppTheme.pageBgColor,
body: NestedScrollView(
controller: controller.scrollController,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
expandedHeight: expandedHeight,
floating: false,
pinned: true,
backgroundColor: Colors.white.withOpacity(controller.opacity),
elevation: 0,
// 左侧返回按钮
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: AppTheme.colorfff,
size: 40.w,
),
onPressed: () => Get.back(),
),
// 标题(跟随透明度渐变显示)
title:TextWidget.body(
'我的粉丝',
size: 32.sp,
color: AppTheme.colorfff,
weight: FontWeight.w600,
),
// 背景图区域
flexibleSpace: FlexibleSpaceBar(
background: _buildHeaderBackground(),
// 渐变遮罩(可选,让导航栏过渡更自然)
collapseMode: CollapseMode.pin,
),
),
];
},
// body 部分使用 SmartRefresher
body: SmartRefresher(
controller: controller.refreshController,
enablePullUp: true,
onRefresh: controller.onRefresh,
onLoading: controller.onLoading,
header: const SmartRefresherHeaderWidget(),
footer: SmartRefresherFooterWidget(textColor: AppTheme.colorfff),
child: ListView.separated(
padding: EdgeInsets.symmetric(horizontal: 30.w, vertical: 20.w),
itemCount: 30,
itemBuilder: (context, index) => _buildListItem(index),
separatorBuilder: (context, index) => Divider(
height: 1,
color: AppTheme.dividerColor,
),
),
),
),
);
},
);
}
}
dart
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
class TeamController extends GetxController {
TeamController();
List items = [];
// 滚动控制器
final ScrollController scrollController = ScrollController();
// 渐变系数 0-1
double opacity = 0.0;
// 滚动开始变化的位置
final double scrollStartPoint = 20.0;
// 滚动结束变化的位置
final double scrollEndPoint = 120.0;
_initData() {
update(["team"]);
}
@override
void onInit() {
super.onInit();
// 监听滚动
scrollController.addListener(() {
// 计算 0-1 之间的渐变系数
double newOpacity;
if (scrollController.offset <= scrollStartPoint) {
// 开始点之前完全透明
newOpacity = 0.0;
} else if (scrollController.offset >= scrollEndPoint) {
// 结束点之后完全不透明
newOpacity = 1.0;
} else {
// 在开始点和结束点之间线性计算
newOpacity = (scrollController.offset - scrollStartPoint) / (scrollEndPoint - scrollStartPoint);
// 确保值在0-1范围内并保留更多小数位精度
newOpacity = double.parse(newOpacity.toStringAsFixed(3)).clamp(0.0, 1.0);
}
// 只有当透明度变化时才更新UI
if ((opacity - newOpacity).abs() > 0.001) {
opacity = newOpacity;
update(["team"]);
}
});
_initData();
}
@override
void onReady() {
super.onReady();
_initData();
}
@override
void onClose() {
super.onClose();
scrollController.dispose();
refreshController.dispose();
}
/*
* 分页
* refreshController:分页控制器
* _page:分页
* _limit:每页条数
* _loadNewsSell:拉取数据(是否刷新)
* onLoading:上拉加载新商品
* onRefresh:下拉刷新
* */
final RefreshController refreshController = RefreshController(
initialRefresh: true,
);
// int _page = 1;
Future<bool> _loadNewsSell(bool isRefresh) async {
return false;
// var result = await HomeApi.noticesList(PageListReq(
// pageNo:isRefresh ? 1:_page,
// pageSize:20
// ));
// if(isRefresh){
// _page = 1;
// items.clear();
// }
// if(result.isNotEmpty){
// _page++;
// items.addAll(result);
// }
// // 是否是空
// return result.isEmpty;
}
// 上拉载入新商品
void onLoading() async {
if (items.isNotEmpty) {
try {
// 拉取数据是否为空 ? 设置暂无数据 : 加载完成
var isEmpty = await _loadNewsSell(false);
isEmpty
? refreshController.loadNoData()
: refreshController.loadComplete();
} catch (e) {
refreshController.loadFailed(); // 加载失败
}
} else {
refreshController.loadNoData(); // 设置无数据
}
update(["team"]);
}
// 下拉刷新
void onRefresh() async {
try {
await _loadNewsSell(true);
refreshController.refreshCompleted();
// 重置加载状态,确保可以继续上拉加载
refreshController.resetNoData();
} catch (e) {
refreshController.refreshFailed();
}
update(["team"]);
}
}