CSS庞大而复杂,灵活而复杂。如何将CSS规则映射到Flutter控件上确实是一个很大的挑战。CSS有那么多的规则和属性,还有各种简写形式。不管怎么说,要实现CSS的所有效果肯定是不可能的,但是能实现到什么程度,哪些部分还需要去实践。CSS是应用于标签的规则。要实现转换,首先要对标签进行解析,即将文本的结构化数据转换为内存的对象数据。html和applets都是这样。准备简单的解析标签问题不大,有现成的html/xml解析库;关键是如何解析css,实现css规则的各种匹配,后代选择器,级联覆盖覆盖等效果是不现实的。幸运的是,网络上有很多功能强大的现成工具供我们选择。我们的最终目标是将具有css属性的单个节点转化为对应的flutter控件,所以我们首先需要获取单个节点的css属性是什么?如果我们直接将css文件中的各种属性转换成内联样式,那么在解析节点的时候就会知道当前节点对应的所有css属性,所以我们需要想办法转换成内联样式的css库或者工具样式。目标明确了,怎么做其实很简单。@team-griffin/css-longhand、css-longhand、css-shorthand-expand、css-shorthand-expanders、fela-plugin-expand-shorthand、grunt-css等工具有很多,随便查一下-longhand,inline-style-expand-shorthand等。最流行的是juice,所以我们解析的是juice转换后的html/xml文件,使用下面的类表示单个节点的CSS:classCSSStyle{final地图<字符串,字符串>_attrs;constCSSStyle(this._attrs);细绳?operator[](Stringkey)=>_attrs[key];双倍的?_getDouble(Stringkey)=>_attrs[key]?.let((it)=>double.tryParse(it));}css的作用CSS不仅可以帮助我们判断当前节点的控件类型,还具有一些额外的padding/margin等控件,将这些属性对应的控件作为父节点放在当前节点的控件上,类似如下:Widgetw=builder.build(element,children);CSSStylecss=...;finalpadding=css.padding;if(padding!=null){w=Padding(padding:padding,child:w,);}finalmargin=css.margin;if(margin!=null){w=Padding(填充:margin,child:w,);}因为flutter的控件非常丰富和强大,其核心思想是充分利用现有控件的组合;当然可以像kraken自带的控件一样画出实体的解决方案,但是需要非常深入的flutter渲染技巧,所以先不实现开始分析.position属性的问题是如何实现position属性。详细的介绍可以参考MDN。它的值主要包括相对的、绝对的、固定的。静态值等于没有设定值。relative属性的含义很容易理解。实际上它是偏移量:finalpositionCSS=css['position'];if(positionCSS=='relative'){finalleft=css._getDouble('left');最后top=css._getDouble('top');finalright=css._getDouble('right');最后底部=css._getDouble('底部');最后dx=左??对吗?.let((it)=>-right);最后dy=top??底部?.let((it)=>-底部);if(dx!=null||dy!=null){w=Transform.translate(offset:Offset(dx??0,你吗??0,),孩子:w,);}}left,top是dx,dy,right,bottom是-dx,-dyabsolute比较好理解,absolute元素不参与兄弟元素布局做好了,就是相对于父节点的偏移量,那么这个布局的效果在Android中是FrameLayout,在flutter中是对应的Stack。理解起来并不难,但在实践中有点棘手。声明为绝对的元素或节点将被忽略。对应什么样的控件?它的父节点首先必须是一个Stack。这是什么意思?这意味着我们在解析一个节点对应的控件时,必须考虑其子节点的属性!这不再是一个对应的问题,是解析问题。使用下面的类来表示html/xml中的一个节点:class_AssembleElement{finalStringname;最终的CSSStyle样式;最后的字符串?类;最终地图<字符串,字符串>?额外的;最终列表<_AssembleElement>子项;_AssembleElement(this.name,this.style,this.klass,this.extra,this.children);@overrideStringtoString(){return'<$namestyle="$style"${extra?.let((it)=>'extra="$extra"')??''}>';}}style是style=""中的内联css属性集合,extra表示节点除了class和style之外其实class可以省略,但是因为做一些调试操作比较方便,所以可以单独取出。所以我们在判断当前节点应该对应哪个控件的地方加入如下逻辑:Widgetbuild(_AssembleElemente,List
