突破了被一个 Flutter 网页解析Table标签样式困一天的难题 |8月更文挑战

656 阅读3分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

废话开篇:对于网页中超出父级标签部分的展示方式大家应该很熟悉,可以设置为滚动、切除等,但是在flutter开发中就遇到了这样的一个难题,table标签的宽度大于屏幕宽度,这样的情况下,flutter会UI超限警告,真的是搞了一天,还是自己太年轻,下面简单记录一下之间摸索的方法及误区。

话不多说,大家先看报错截图:

image.png

由于table表格的最小宽度还是超过了屏幕,这里也是黄牌警告了。

正确的解决方式

这里是html组件的全部内容,大家要注意的是里面有个 customRender 参数,这里就是传对于html标签的通用渲染方式,意思就是在渲染table标签的时候需要单独进行渲染,在代码中添加一个 SingleChildScrollView 横向滚动的组件,实现超过屏幕部分的table可以以滚动的方式浏览全部,这样也就满足了布局要求,去掉了黄牌警告。

child: new Container(
  padding: EdgeInsets.only(left: 0,right: 10),
  child: new Html(
    shrinkWrap: false,
    data: detailArticle != null ? detailArticle!.content + '<p style="font-size:11px">阅读量:'+ detailArticle!.readNum.toString() + '</p>' : '',
    style: {
      '*':Style(color: Colors.black,letterSpacing: 3,lineHeight: LineHeight(1.7),fontFamily: "SY",fontSize:FontSize(16) ,fontWeight: FontWeight.w500),
    },
    customRender: {
      "table": (context, child) {
        return SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child:
          (context.tree as TableLayoutElement).toWidget(context),
        );
      },
    },
    // navigationDelegateForIframe: navigationDelegate,
  ),
),

上面的代码其实真的是没有想到 flutter 还可以这样秀。

接下来说一下解决问题中走过的弯路。

弯路 一

单独给组件 html 添加水平滚动方向的 SingleChildScrollView 。无效,html 组件的宽度是不会改变的,所以添加水平滚动组件实际是没有意义的。

弯路 二

解析后台返回的网页标签,修改 table 标签的属性。无效,无论是在全局加上css样式并添加最高权重还是逐一标签解析直接修改 table 标签的属性都是徒劳的,这里展示一下解析的一些操作代码。

//引入 dom 库
import 'package:html/dom.dart' as DOM;

先简单的描述一下解析意图:递归式解析所有标签,找到 table 标签,修改 table 标签的 attributesstyle 的相关属性(文字可以折行、宽度最大100%)或者在 table 标签 外层嵌套一层 div 标签并设置其 style 的overfloat 属性为 scroll,结果可想而知,都是无效的。不过也总结了一些flutterdom 解析的一些知识细节。

代码仅供交流,代码拙劣,不敢弄斧。

//解析网页demo
static void parseSpecialElement(DOM.Element element,DOM.Element tempElement){
  for(int i = 0;i < element.children.length;i++){
    DOM.Element childElement = element.children[i];
    DOM.Element nextElement = new DOM.Element.tag(childElement.localName);
    if(childElement.localName.toString() == 'table') {
      //EventBusUtils.getInstance().fire(new WSlArticleWidthNeedChange(isNeedChangeWidth: true));
      DOM.Element divElement = new DOM.Element.tag('div');
      LinkedHashMap<Object, String> divAttributes = new LinkedHashMap();
      divAttributes['style'] = 'width: 100px;height: 300px;background-color: red;';
      divElement.attributes = divAttributes;
      LinkedHashMap<Object, String> newAttributes = new LinkedHashMap();
      newAttributes['style'] = 'white-space:normal;width: 100%;table-layout: fixed; word-break: break-all;';
      nextElement.attributes = newAttributes;
      if(childElement.children.length == 0){
        nextElement.text = childElement.text;
      } else {
        parseSpecialElement(childElement,nextElement);
      }
      divElement.append(nextElement);
      tempElement.append(divElement);
      //debugPrint(childElement.attributes.toString());
    } else if(childElement.localName.toString() == 'td') {
      LinkedHashMap<Object, String> newAttributes = new LinkedHashMap();
      newAttributes['style'] = 'white-space:normal;word-break: break-all;';
      nextElement.attributes = newAttributes;
      if(childElement.children.length == 0){
        nextElement.text = childElement.text;
      } else {
        parseSpecialElement(childElement,nextElement);
      }
      tempElement.append(nextElement);
    } else {
      if(childElement.children.length == 0){
        //debugPrint('childElement = ' + childElement.outerHtml);
        nextElement.text = childElement.text;
      } else {
        parseSpecialElement(childElement,nextElement);
      }
      nextElement.attributes = childElement.attributes;
      tempElement.append(nextElement);
    }
  }
}

下面展示一下正常查看 table 标签过宽时候的方式。

屏幕录制2021-08-18 下午3.53.06.gif

没有什么特别难的技术,只是遇到问题写下来,真是绕了一大圈弯路,错误的路不代表它会指导你成功,但它至少会告诉你它为你找到正确的方向提供了一次借鉴,记录一下,代码拙劣,大神勿喷,如果对大家有帮助,更是深感欣慰。