Flutter 无需SyncFusion等授权插件实现体重身高线性标尺及单位换算
体重/身高线性刻度标尺实现方案
1 Custom Paint 绘制实现步骤
- 先定义刻度基础配置:单个刻度的像素宽度、最小/最大数值、刻度步长(比如体重步长设为0.1kg)、长/短刻度的长度、配色
- 计算可见刻度范围:根据当前滚动偏移,算出当前可视区域内需要绘制的刻度起始和结束下标,避免绘制不可见内容提升性能
- 区分刻度样式:整数值对应长刻度+数值标签,小数位对应短刻度无标签;中间选中位置的刻度用高亮色、更长的尺寸突出显示
- 滚动偏移转数值逻辑:
当前选中数值 = 最小数值 + (滚动偏移量 / 单个刻度像素宽度) * 刻度步长,计算结果保留对应小数位即可
2 单位联动逻辑实现
统一用kg作为内部计算基准值,换算规则为 1kg = 2.20462lb,对应双向换算公式:
- kg转lb:
lb数值 = kg数值 * 2.20462 - lb转kg:
kg数值 = lb数值 / 2.20462
联动逻辑:
- 任意单位的标尺滑动触发数值变更时,先更新基准kg数值,再通过换算公式计算另一单位的对应数值,同步更新另一标尺的滚动位置和输入框显示
- 输入框手动修改数值时,先判定当前输入的单位,换算为基准kg值后,再同步更新两个标尺的位置和另一单位的输入框数值
3 核心代码示例(Flutter 环境)
刻度绘制核心逻辑
class RulerPainter extends CustomPainter { final double scrollOffset; final double selectedValue; final double minValue; final double maxValue; final double step = 0.1; final double scaleWidth = 8; // 单个刻度占8像素宽度 RulerPainter({required this.scrollOffset, required this.selectedValue, required this.minValue, required this.maxValue}); @override void paint(Canvas canvas, Size size) { final normalPaint = Paint()..color = Colors.grey.shade300..strokeWidth = 1; final highlightPaint = Paint()..color = Colors.blue..strokeWidth = 2; final centerX = size.width / 2; // 绘制所有可见刻度 final startIndex = (scrollOffset / scaleWidth).floor() - 20; final endIndex = (scrollOffset + size.width) ~/ scaleWidth + 20; for (int i = startIndex; i <= endIndex; i++) { if (i < 0 || minValue + i * step > maxValue) continue; final x = i * scaleWidth - scrollOffset; final currentValue = minValue + i * step; // 整数值刻度更长,且显示文本 final scaleHeight = currentValue % 1 == 0 ? 30 : 15; final paint = (currentValue - selectedValue).abs() < 0.05 ? highlightPaint : normalPaint; canvas.drawLine(Offset(x, 0), Offset(x, scaleHeight), paint); if (currentValue % 1 == 0) { TextSpan span = TextSpan(text: currentValue.toInt().toString(), style: TextStyle(color: Colors.grey, fontSize: 12)); TextPainter tp = TextPainter(text: span, textDirection: TextDirection.ltr)..layout(); tp.paint(canvas, Offset(x - tp.width / 2, scaleHeight + 5)); } } // 绘制中间选中指示器 canvas.drawLine(Offset(centerX, 0), Offset(centerX, 40), highlightPaint); } @override bool shouldRepaint(covariant RulerPainter oldDelegate) { return oldDelegate.scrollOffset != scrollOffset || oldDelegate.selectedValue != selectedValue; } }
单位联动逻辑
class WeightController extends ChangeNotifier { // 内部统一用kg作为基准存储 double _weightKg = 55.0; double get weightKg => _weightKg; double get weightLb => _weightKg * 2.20462; // 切换kg数值 void updateByKg(double kg) { _weightKg = kg; notifyListeners(); } // 切换lb数值 void updateByLb(double lb) { _weightKg = lb / 2.20462; notifyListeners(); } }
4 实现效果预览

内容的提问来源于stack exchange,提问作者Vamsee.
相关产品推荐
相关产品推荐

