view
js
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:happy/common/index.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'index.dart';
class NoticeDetailPage extends GetView<NoticeDetailController> {
const NoticeDetailPage({super.key});
// 头部
Widget _buildHeader() {
return <Widget>[
TextWidget.body(
controller.title,
size: 28.sp,
weight: FontWeight.w600,
color: AppTheme.color000,
),
SizedBox(
height: 20.w,
),
<Widget>[
Icon(
Icons.access_time_outlined,
size: 28.sp,
color: AppTheme.color000,
),
SizedBox(
width: 10.w,
),
TextWidget.body(
controller.time,
color: AppTheme.color666,
),
].toRow(mainAxisAlignment: MainAxisAlignment.center)
]
.toColumn(crossAxisAlignment: CrossAxisAlignment.center)
.paddingOnly(top: 20.w, bottom: 20.w)
.card(color: AppTheme.dividerColor2);
}
// 内容详情
Widget _buildContent() {
return <Widget>[
HtmlWidget(
controller.content,
// 设置渲染模式
renderMode: RenderMode.column,
// 设置文本样式
textStyle: TextStyle(
fontSize: 28.sp,
color: Colors.white,
height: 1.5,
),
),
]
.toColumn(crossAxisAlignment: CrossAxisAlignment.center)
.paddingAll(30.w)
.card(color: AppTheme.dividerColor2);
}
// 主视图
Widget _buildView() {
// 系统状态栏占位高度
double systemStatusBarHeight = MediaQuery.of(Get.context!).padding.top;
// 总占位高度
double systemTotalHeight = 44 + systemStatusBarHeight;
return SingleChildScrollView(
controller: controller.scrollController,
child: <Widget>[
SizedBox(height: systemTotalHeight,),
_buildHeader(),
SizedBox(height: 20.w,),
_buildContent(),
].toColumn(crossAxisAlignment: CrossAxisAlignment.start).paddingHorizontal(30.w),
);
}
@override
Widget build(BuildContext context) {
return GetBuilder<NoticeDetailController>(
init: NoticeDetailController(),
id: "notice_detail",
builder: (_) {
return Scaffold(
backgroundColor: AppTheme.pageBgColor,
body: <Widget>[
ImgWidget(path: 'assets/images/home11.png',width: 750.w,height: 500.w,),
_buildView().expanded(),
// 只刷新导航栏
GetBuilder<NoticeDetailController>(
id: "notice_detail_navbar",
builder: (_) => AnimatedContainer(
duration: const Duration(milliseconds: 100),
color: Colors.white.withOpacity(controller.opacity),
child: TDNavBar(
height: 44,
title: '消息详情',
titleColor: AppTheme.color000,
titleFontWeight: FontWeight.w600,
backgroundColor: Colors.transparent,
screenAdaptation: true,
useDefaultBack: false,
leftBarItems: [
TDNavBarItem(
icon: TDIcons.chevron_left,
iconSize: 24,
iconColor: AppTheme.color000,
action: () {
Get.back();
}
),
],
),
),
),
].toStack(),
);
},
);
}
}
controller
js
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:happy/common/index.dart';
class NoticeDetailController extends GetxController {
NoticeDetailController();
// 滚动控制器
final ScrollController scrollController = ScrollController();
// 渐变系数 0-1
double opacity = 0.0;
// 滚动开始变化的位置
final double scrollStartPoint = 20.0;
// 滚动结束变化的位置
final double scrollEndPoint = 120.0;
int id = 0;
String title = '';
String content = '测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试';
String time = '';
_initData() async {
id = Get.arguments['id'];
var res = await HomeApi.noticeDetail(id);
content = res.content ?? '';
title = res.title ?? '';
time = res.updatedAt ?? '';
update(["notice_detail"]);
}
@override
void onReady() {
super.onReady();
_initData();
}
@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(["notice_detail_navbar"]);
}
});
_initData();
}
@override
void onClose() {
scrollController.dispose();
super.onClose();
}
}