Flutter中实现文本列最大长度适配与小数对齐的方法
Flutter实现两列对齐:首列自适应最长项宽度,次列按小数位对齐
需求说明
需要实现两种对齐效果:
- 第一列宽度由列表中最长文本的长度决定,所有首列文本左对齐且宽度一致
- 第二列按小数点对齐,确保所有数字的小数点处于同一竖线位置
给定数据:
Map<String,dynamic> map={ 'FootBall':200.30, 'Hockey':3.30, 'Golf':30.400 };
现有代码无法实现目标对齐效果,以下是解决方案:
实现步骤与代码
1. 计算首列最大宽度
通过TextPainter计算所有首列文本的渲染宽度,取最大值作为首列固定宽度,保证所有项宽度统一。
2. 拆分数字实现小数点对齐
将数字拆分为整数和小数部分,整数部分右对齐、小数部分左对齐,配合基线对齐确保小数点位置一致。
完整代码示例
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center(child: const AlignDemo()), ), ); } } class AlignDemo extends StatefulWidget { const AlignDemo({super.key}); @override State<AlignDemo> createState() => _AlignDemoState(); } class _AlignDemoState extends State<AlignDemo> { final Map<String, dynamic> map = { 'FootBall': 200.30, 'Hockey': 3.30, 'Golf': 30.400, }; // 计算首列最长文本的渲染宽度 double getMaxLabelWidth(BuildContext context) { double maxWidth = 0; final textStyle = DefaultTextStyle.of(context).style; for (var key in map.keys) { final textPainter = TextPainter( text: TextSpan(text: key, style: textStyle), textDirection: TextDirection.ltr, )..layout(minWidth: 0, maxWidth: double.infinity); if (textPainter.width > maxWidth) maxWidth = textPainter.width; } return maxWidth; } // 将数字拆分为整数和小数部分 Map<String, String> splitNumber(num number) { String numStr = number.toString(); if (numStr.contains('.')) { List<String> parts = numStr.split('.'); return {'integer': parts[0], 'decimal': parts[1]}; } else { return {'integer': numStr, 'decimal': ''}; } } // 计算整数部分的最大渲染宽度(优化对齐精度) double getMaxIntegerWidth(BuildContext context) { double maxWidth = 0; final textStyle = DefaultTextStyle.of(context).style; for (var value in map.values) { String integerPart = splitNumber(value)['integer']!; final textPainter = TextPainter( text: TextSpan(text: integerPart, style: textStyle), textDirection: TextDirection.ltr, )..layout(minWidth: 0, maxWidth: double.infinity); if (textPainter.width > maxWidth) maxWidth = textPainter.width; } return maxWidth; } @override Widget build(BuildContext context) { final maxLabelWidth = getMaxLabelWidth(context); final maxIntegerWidth = getMaxIntegerWidth(context); return Container( color: Colors.grey, height: 200, width: 300, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: map.keys.map((e) { final numParts = splitNumber(map[e]); return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ // 首列固定宽度,左对齐 SizedBox( width: maxLabelWidth, child: Text(e, textAlign: TextAlign.left), ), const SizedBox(width: 8), const Text(':'), const SizedBox(width: 8), // 整数部分右对齐,确保小数点对齐 SizedBox( width: maxIntegerWidth, child: Text(numParts['integer']!, textAlign: TextAlign.right), ), // 显示小数部分 if (numParts['decimal']!.isNotEmpty) Text('.${numParts['decimal']}'), ], ), ); }).toList(), ), ); } }
效果说明
运行代码后将得到目标对齐效果:
FootBall : 200.30 Hockey : 3.30 Golf : 30.400
内容的提问来源于stack exchange,提问作者Irfan Ganatra
相关产品推荐
相关产品推荐

