#
前言
体重管理是很多人关注的健康话题,体重趋势页面需要展示体重的变化曲线,帮助用户了解自己的体重变化规律。通过可视化的图表,用户可以直观地看到减重或增重的效果。
这篇文章会讲解体重趋势页面的实现,包括汇总数据卡片和趋势图表两个核心组件。我们会用到 fl_chart 库来绘制折线图。
页面整体结构
体重趋势页面结构简洁,主要包含汇总数据卡片和趋势图表两个部分。
dart
class WeightTrendPage extends StatelessWidget {
const WeightTrendPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFFAFAFC),
appBar: AppBar(
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios_rounded, size: 20.w),
onPressed: () => Get.back()
),
title: Text('体重趋势', style: TextStyle(fontSize: 17.sp, fontWeight: FontWeight.w600)),
centerTitle: true,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(20.w),
child: Column(
children: [
_buildSummaryCard(),
SizedBox(height: 20.h),
_buildChart(),
],
),
),
);
}
}
页面使用统一的浅灰色背景,AppBar 透明背景配合居中标题。两个卡片垂直排列,间距为 20.h。
汇总数据卡片
汇总卡片展示当前体重、目标体重和本月变化三个关键数据。
dart
Widget _buildSummaryCard() {
return Container(
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.r)
),
child: Row(
children: [
_buildSummaryItem('当前', '65.5 kg', const Color(0xFF6C63FF)),
_buildSummaryItem('目标', '63 kg', const Color(0xFF00C9A7)),
_buildSummaryItem('本月', '-1.2 kg', const Color(0xFFFF6B6B)),
],
),
);
}
Widget _buildSummaryItem(String label, String value, Color color) {
return Expanded(
child: Column(
children: [
Text(label, style: TextStyle(fontSize: 12.sp, color: Colors.grey[500])),
SizedBox(height: 6.h),
Text(value, style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w700,
color: color
)),
],
),
);
}
三个数据项用 Expanded 平均分配宽度,每个项目垂直排列标签和数值。当前体重用紫色(应用主题色),目标体重用绿色(表示积极目标),本月变化用红色(表示减重)。
如果本月体重增加,可以把颜色改成其他颜色,或者根据用户的目标(减重/增重)来动态调整颜色。
体重变化方向判断
根据用户的目标和实际变化,可以给出不同的视觉反馈:
dart
Color _getChangeColor(double change, String goal) {
if (goal == '减重') {
return change < 0 ? const Color(0xFF00C9A7) : const Color(0xFFFF6B6B);
} else if (goal == '增重') {
return change > 0 ? const Color(0xFF00C9A7) : const Color(0xFFFF6B6B);
} else {
return const Color(0xFF6C63FF);
}
}
String _formatChange(double change) {
if (change > 0) {
return '+${change.toStringAsFixed(1)} kg';
} else if (change < 0) {
return '${change.toStringAsFixed(1)} kg';
} else {
return '0 kg';
}
}
减重目标下,体重下降显示绿色,体重上升显示红色;增重目标下则相反。这种设计让用户能直观地了解自己是否朝着目标前进。
趋势图表组件
趋势图表是这个页面的核心,用折线图展示体重的变化趋势。
dart
Widget _buildChart() {
return Container(
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.r)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('30天趋势', style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: const Color(0xFF1A1A2E)
)),
SizedBox(height: 20.h),
SizedBox(
height: 200.h,
child: LineChart(
LineChartData(
gridData: FlGridData(show: false),
titlesData: FlTitlesData(
rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: false))
),
borderData: FlBorderData(show: false),
lineBarsData: [
LineChartBarData(
spots: const [
FlSpot(0, 66.5), FlSpot(1, 66.2), FlSpot(2, 66.0),
FlSpot(3, 65.8), FlSpot(4, 65.7), FlSpot(5, 65.5), FlSpot(6, 65.5)
],
isCurved: true,
color: const Color(0xFF6C63FF),
barWidth: 3,
dotData: FlDotData(show: false),
belowBarData: BarAreaData(
show: true,
color: const Color(0xFF6C63FF).withOpacity(0.1)
),
),
],
minY: 64, maxY: 68,
),
),
),
],
),
);
}
图表使用 fl_chart 库的 LineChart 组件。gridData 设置为不显示网格线,让图表看起来更简洁。titlesData 隐藏了左、右、上三边的标签,只保留底部。
折线设置为平滑曲线(isCurved: true),线宽 3 像素,不显示数据点。belowBarData 在折线下方添加了一层淡紫色的填充区域,增强视觉效果。
Y轴范围设置为 64-68,这个范围根据实际数据动态计算会更合理。
动态计算Y轴范围
为了让图表显示效果更好,Y轴范围应该根据实际数据动态计算:
dart
Map<String, double> _calculateYRange(List<double> values) {
if (values.isEmpty) {
return {'min': 0, 'max': 100};
}
final min = values.reduce((a, b) => a < b ? a : b);
final max = values.reduce((a, b) => a > b ? a : b);
final range = max - min;
// 留出一些边距
final padding = range * 0.2;
return {
'min': (min - padding).floorToDouble(),
'max': (max + padding).ceilToDouble(),
};
}
这个方法计算数据的最小值和最大值,然后在两端各留出 20% 的边距,让图表不会太拥挤。
时间范围选择
用户可能想查看不同时间范围的趋势,可以添加一个时间范围选择器:
dart
Widget _buildTimeRangeSelector() {
final ranges = ['7天', '30天', '90天', '1年'];
final selectedIndex = 1; // 默认选中30天
return Row(
children: ranges.asMap().entries.map((entry) {
final isSelected = entry.key == selectedIndex;
return Expanded(
child: GestureDetector(
onTap: () {
// 切换时间范围
},
child: Container(
margin: EdgeInsets.only(right: entry.key < ranges.length - 1 ? 8.w : 0),
padding: EdgeInsets.symmetric(vertical: 8.h),
decoration: BoxDecoration(
color: isSelected
? const Color(0xFF6C63FF)
: const Color(0xFF6C63FF).withOpacity(0.1),
borderRadius: BorderRadius.circular(8.r),
),
child: Center(
child: Text(
entry.value,
style: TextStyle(
fontSize: 12.sp,
color: isSelected ? Colors.white : const Color(0xFF6C63FF),
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
),
),
),
),
),
);
}).toList(),
);
}
四个时间范围选项横向排列,选中的用实心背景,未选中的用淡色背景。这种设计让用户能快速切换查看不同时间段的趋势。
目标线展示
在图表中添加一条目标线,让用户能直观地看到当前体重和目标的差距:
dart
LineChartBarData _buildGoalLine(double goalWeight) {
return LineChartBarData(
spots: [
FlSpot(0, goalWeight),
FlSpot(6, goalWeight),
],
isCurved: false,
color: const Color(0xFF00C9A7),
barWidth: 1.5,
dotData: FlDotData(show: false),
dashArray: [5, 5], // 虚线
);
}
目标线用绿色虚线表示,和实际体重曲线形成对比。用户可以清楚地看到自己距离目标还有多远。
数据点详情
当用户点击图表上的某个点时,可以显示该点的详细信息:
dart
Widget _buildTooltip(double weight, String date) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
decoration: BoxDecoration(
color: const Color(0xFF1A1A2E),
borderRadius: BorderRadius.circular(8.r),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${weight.toStringAsFixed(1)} kg',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
Text(
date,
style: TextStyle(
fontSize: 11.sp,
color: Colors.white70,
),
),
],
),
);
}
提示框用深色背景,显示体重值和日期。这种交互让用户能查看具体某一天的数据。
趋势分析文字
除了图表,还可以添加一段趋势分析的文字说明:
dart
Widget _buildTrendAnalysis(double change, int days) {
String analysis;
if (change < -1) {
analysis = '过去$days天体重下降明显,继续保持!';
} else if (change < 0) {
analysis = '过去$days天体重稳步下降,效果不错。';
} else if (change == 0) {
analysis = '过去$days天体重保持稳定。';
} else if (change < 1) {
analysis = '过去$days天体重略有上升,注意饮食。';
} else {
analysis = '过去$days天体重上升较多,建议调整计划。';
}
return Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: const Color(0xFF6C63FF).withOpacity(0.08),
borderRadius: BorderRadius.circular(10.r),
),
child: Row(
children: [
Icon(Icons.insights_rounded, size: 18.w, color: const Color(0xFF6C63FF)),
SizedBox(width: 8.w),
Expanded(
child: Text(
analysis,
style: TextStyle(fontSize: 13.sp, color: const Color(0xFF6C63FF)),
),
),
],
),
);
}
根据体重变化自动生成分析文字,给用户提供个性化的反馈和建议。
小结
体重趋势页面通过汇总数据卡片和趋势图表两个组件,帮助用户全面了解自己的体重变化情况。
核心设计要点包括:三个关键数据用不同颜色区分,折线图下方添加淡色填充增强视觉效果,目标线用虚线表示便于对比。这些设计让用户能直观地追踪自己的体重管理进度。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net