Flutter中使用html包无法展示HTML表格字符串怎么办?
解决Flutter html包无法正确渲染HTML表格的问题
问题说明
- 预期效果:需要渲染一个规整的两列布局表格,包含员工信息、各项参数(ID、日期、地点等)以及底部的备注输入框,整体宽度占满,单元格有适配的内边距和宽度分配。
- 实际问题:使用Flutter的
html包渲染时,表格布局错乱,单元格宽度、内边距未按HTML内联样式生效,完全不符合设计要求。
需要渲染的HTML字符串:
<table id='ParametersTable' style='width:100%'> <thead> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <label class='col-form-label'>Employee</label> </td> <td colspan='8' style='padding: 2px 10px 2px 10px; width: 66.66666666666666%'>1003 - Abdulsamed Demirtop</td> </tr> </thead> <tbody class='parambody'> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <input id='1030' name ='1030' value='1030' hidden /> <label class='col-form-label'>Id</label> </td> <td colspan='7' style='padding: 2px 10px 2px 10px; width: 58.333333333333336%'>4</td> <td colspan='1' style='padding: 2px 0px 2px 0px; width: 8.333333333333332%'></td> </tr> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <input id='1032' name ='1032' value='1032' hidden /> <label class='col-form-label'>FromDate</label> </td> <td colspan='7' style='padding: 2px 10px 2px 10px; width: 58.333333333333336%'>25/Dec/2022 11:30 AM</td> <td colspan='1' style='padding: 2px 0px 2px 0px; width: 8.333333333333332%'></td> </tr> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <input id='1033' name ='1033' value='1033' hidden /> <label class='col-form-label'>EndDate</label> </td> <td colspan='7' style='padding: 2px 10px 2px 10px; width: 58.333333333333336%'>28/Dec/2022 11:30 PM</td> <td colspan='1' style='padding: 2px 0px 2px 0px; width: 8.333333333333332%'></td> </tr> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <input id='1034' name ='1034' value='1034' hidden /> <label class='col-form-label'>Country</label> </td> <td colspan='7' style='padding: 2px 10px 2px 10px; width: 58.333333333333336%'>Turkiye</td> <td colspan='1' style='padding: 2px 0px 2px 0px; width: 8.333333333333332%'></td> </tr> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <input id='1035' name ='1035' value='1035' hidden /> <label class='col-form-label'>City</label> </td> <td colspan='7' style='padding: 2px 10px 2px 10px; width: 58.333333333333336%'>Ankara</td> <td colspan='1' style='padding: 2px 0px 2px 0px; width: 8.333333333333332%'></td> </tr> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <input id='1036' name ='1036' value='1036' hidden /> <label class='col-form-label'>Type</label> </td> <td colspan='7' style='padding: 2px 10px 2px 10px; width: 58.333333333333336%'>Flight</td> <td colspan='1' style='padding: 2px 0px 2px 0px; width: 8.333333333333332%'></td> </tr> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%'> <input id='1037' name ='1037' value='1037' hidden /> <label class='col-form-label'>Purpose</label> </td> <td colspan='7' style='padding: 2px 10px 2px 10px; width: 58.333333333333336%'>Meeting</td> <td colspan='1' style='padding: 2px 0px 2px 0px; width: 8.333333333333332%'></td> </tr> </tbody> <tfoot> <tr> <td colspan='4' style='padding: 2px 10px 2px 10px; width: 33.33333333333333%; white-space: nowrap'> <label class='col-form-label'>Notes</label> </td> <td colspan='8' style='padding: 2px 10px 2px 10px; width: 66.66666666666666%'> <input id='notes' name='notes' autocomplete='off' style='width: 100%' class='form-control' /> </td> </tr> </tfoot> </table>
解决方案
Flutter基础html包对复杂表格样式支持有限,尤其是colspan和内联宽度、内边距的解析容易失效,可以通过以下方式解决:
1. 更换为flutter_html增强包
flutter_html对HTML/CSS的支持更完善,能更好解析表格样式:
- 添加依赖到
pubspec.yaml:
dependencies: flutter_html: ^3.0.0-beta.2 # 或最新稳定版
- 使用组件渲染:
import 'package:flutter_html/flutter_html.dart'; Html( data: yourHtmlString, style: { "table": Style( width: MediaQuery.of(context).size.width, ), "td": Style( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2), ), "label": Style( fontWeight: FontWeight.bold, ), }, )
2. 简化HTML结构并补充样式
去掉冗余的colspan设置,直接用两列布局,再通过Flutter样式增强:
修改后的HTML:
<table id='ParametersTable' style='width:100%; border-collapse: collapse;'> <thead> <tr> <td style='padding: 2px 10px; width: 33%; border: 1px solid #eee;'><label class='col-form-label'>Employee</label></td> <td style='padding: 2px 10px; width: 67%; border: 1px solid #eee;'>1003 - Abdulsamed Demirtop</td> </tr> </thead> <tbody class='parambody'> <tr> <td style='padding: 2px 10px; width: 33%; border: 1px solid #eee;'><label class='col-form-label'>Id</label></td> <td style='padding: 2px 10px; width: 67%; border: 1px solid #eee;'>4</td> </tr> <!-- 其他行按此格式修改 --> <tr> <td style='padding: 2px 10px; width: 33%; border: 1px solid #eee;'><label class='col-form-label'>Notes</label></td> <td style='padding: 2px 10px; width: 67%; border: 1px solid #eee;'><input id='notes' name='notes' autocomplete='off' style='width: 100%' class='form-control' /></td> </tr> </tbody> </table>
用基础html包渲染时包裹在容器中:
import 'package:flutter/material.dart'; import 'package:html/parser.dart' show parse; import 'package:html/dom.dart' as dom; Widget buildHtmlTable(String html) { return Container( width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 16), child: HtmlWidget( html, webView: false, textStyle: TextStyle(fontSize: 14), ), ); }
3. 手动解析HTML构建原生Table
如果对样式要求极高,直接用Flutter原生Table组件构建:
import 'package:flutter/material.dart'; import 'package:html/parser.dart' show parse; Widget buildNativeTable(String html, BuildContext context) { final document = parse(html); final table = document.querySelector('#ParametersTable'); List<TableRow> rows = []; // 处理表头 final theadTr = table.querySelector('thead tr'); final thCells = theadTr.querySelectorAll('td'); rows.add(TableRow( children: [ Padding( padding: EdgeInsets.symmetric(horizontal:10, vertical:2), child: Text(thCells[0].text, style: TextStyle(fontWeight: FontWeight.bold)), ), Padding( padding: EdgeInsets.symmetric(horizontal:10, vertical:2), child: Text(thCells[1].text), ), ], )); // 处理表体 final tbodyTrs = table.querySelectorAll('tbody tr'); for(var tr in tbodyTrs) { final cells = tr.querySelectorAll('td'); rows.add(TableRow( children: [ Padding( padding: EdgeInsets.symmetric(horizontal:10, vertical:2), child: Text(cells[0].querySelector('label').text, style: TextStyle(fontWeight: FontWeight.bold)), ), Padding( padding: EdgeInsets.symmetric(horizontal:10, vertical:2), child: Text(cells[1].text), ), ], )); } // 处理表尾 final tfootTr = table.querySelector('tfoot tr'); final tfootCells = tfootTr.querySelectorAll('td'); rows.add(TableRow( children: [ Padding( padding: EdgeInsets.symmetric(horizontal:10, vertical:2), child: Text(tfootCells[0].text, style: TextStyle(fontWeight: FontWeight.bold)), ), Padding( padding: EdgeInsets.symmetric(horizontal:10, vertical:2), child: TextField( decoration: InputDecoration(border: OutlineInputBorder()), ), ), ], )); return Table( border: TableBorder.all(color: Colors.grey.shade200), columnWidths: { 0: FixedColumnWidth(MediaQuery.of(context).size.width * 0.33), 1: FlexColumnWidth(), }, children: rows, ); }
内容的提问来源于stack exchange,提问作者Samet Demirtop
相关产品推荐
相关产品推荐

