This commit is contained in:
wyf
2025-05-15 13:57:42 +08:00
parent fb5c3864a3
commit 75ddfca402
51 changed files with 2451 additions and 1233 deletions

View File

@@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
class SegmentData {
final Color color;
final double value;
SegmentData({required this.color, required this.value});
}
class SegmentedCirclePainter extends CustomPainter {
final List<SegmentData> segments;
final double strokeWidth;
final double gapAngle; // 每段之间的间隔角度(单位:度)
SegmentedCirclePainter({
required this.segments,
this.strokeWidth = 6.0,
this.gapAngle = 4.0,
});
@override
void paint(Canvas canvas, Size size) {
final double radius = size.width / 2;
final Offset center = Offset(size.width / 2, size.height / 2);
final Paint paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth
..strokeCap = StrokeCap.square;
final double totalValue = segments.fold(0, (sum, item) => sum + item.value);
final double totalGap = gapAngle * segments.length;
final double totalDrawAngle = 360.0 - totalGap;
double startAngle = -90.0; // 从顶部开始
for (var segment in segments) {
final double sweepAngle = (segment.value / totalValue) * totalDrawAngle;
paint.color = segment.color;
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius - strokeWidth / 2),
radians(startAngle),
radians(sweepAngle),
false,
paint,
);
startAngle += sweepAngle + gapAngle;
}
}
double radians(double degrees) => degrees * 3.1415926 / 180;
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
class SegmentedCircleWithCenterWidget extends StatelessWidget {
final List<SegmentData> segments;
final double strokeWidth;
final double gapAngle;
final Widget centerWidget;
const SegmentedCircleWithCenterWidget({
Key? key,
required this.segments,
this.strokeWidth = 6.0,
this.gapAngle = 4.0,
required this.centerWidget,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
CustomPaint(
size: Size(200, 200), // 设置圆的尺寸
painter: SegmentedCirclePainter(
segments: segments,
strokeWidth: strokeWidth,
gapAngle: gapAngle,
),
),
centerWidget, // 放置自定义的中心 Widget
Positioned(
right: 60.rpx, // 放置在右侧
child: SvgPicture.asset(
'assets/img/icon/add.svg',
width: 14.rpx,
height: 22.rpx,
color: themeController.currentColor.sc9,
),
),
],
);
}
}

View File

@@ -0,0 +1,178 @@
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/pages/sleep_report/component/SegmentedCirclePainter.dart';
class SleepScoreWidget extends StatefulWidget {
const SleepScoreWidget({super.key});
@override
State<SleepScoreWidget> createState() => _SleepScoreWidgetState();
}
class _SleepScoreWidgetState extends State<SleepScoreWidget> {
@override
void setState(VoidCallback callback) {
super.setState(callback);
}
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
List<Map<String, dynamic>> showLabel = [
{"level": 1, "name": "优秀(≥85)", "color": Color(0xFF4CAF50)},
{"level": 2, "name": "良好(75~84)", "color": Color(0xFF8BC34A)},
{"level": 3, "name": "合格(60~74)", "color": Color(0xFFFFC107)},
{"level": 4, "name": "注意(60)", "color": Color(0xFFF44336)},
];
return Container(
width: double.infinity,
// decoration: BoxDecoration(color: Colors.green),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(26.rpx, 29.rpx, 26.rpx, 45.rpx),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
decoration: BoxDecoration(),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'30天平均分',
style: TextStyle(
color: Color(0xFFD3D3D3),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
Text(
'79',
style: TextStyle(
color: Colors.white,
fontSize: 48.rpx,
letterSpacing: 0.0,
),
),
].divide(SizedBox(height: 56.rpx)),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(),
child: SegmentedCircleWithCenterWidget(
segments: [
SegmentData(color: Colors.red, value: 30),
SegmentData(color: Colors.green, value: 20),
SegmentData(color: Colors.blue, value: 40),
SegmentData(color: Colors.orange, value: 10),
],
strokeWidth: 8,
gapAngle: 8,
centerWidget: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"睡眠评分",
style: TextStyle(
color: stringToColor("#FFFFFF"),
fontSize:
AppConstants().normal_text_fontSize),
),
Text(
"65",
style: TextStyle(
color: stringToColor("#FF9F66"),
fontSize: 100.rpx),
),
],
),
),
),
),
),
Container(
decoration: BoxDecoration(),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'睡眠等级',
style: TextStyle(
color: Color(0xFFD3D3D3),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
Text(
'合格',
style: TextStyle(
color: stringToColor("#FF9F66"),
fontSize: 48.rpx,
letterSpacing: 0.0,
),
),
].divide(SizedBox(height: 56.rpx)),
),
),
].divide(SizedBox(
width: 33.rpx,
)),
),
),
Wrap(
spacing: 32.rpx,
runSpacing: 20.rpx,
children: showLabel.map<Widget>((item) {
return Container(
padding: EdgeInsets.all(5.rpx),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 20.rpx,
height: 20.rpx,
decoration: BoxDecoration(
color: item["color"],
borderRadius: BorderRadius.circular(10.rpx),
),
),
SizedBox(width: 17.rpx),
Text(
item["name"],
style: TextStyle(
color: Colors.white,
fontSize: 24.rpx,
),
),
],
),
);
}).toList(),
),
],
),
),
);
}
}