• 2015-11-11

    CocoaUI 的 CSS 样式应用算法说明和源码解析

    Views: 25316 | No Comments

    W3C 规范中对 CSS 样式的应用算法有规定, 这个规范中的算法比较复杂, 简单来说, 就是根据 CSS 样式选择器中的不同类型的元素出现的次数来计算优先级, 如果某个节点同时命中多个 CSS 样式规则, 以高优先级的样式为准.

    W3C 规范具体可以见这个文档: http://www.w3.org/TR/CSS2/cascade.html, "6.4.3 Calculating a selector's specificity" 一节.

    例如下面的两条 CSS 样式规则和 HTML:

    <style>
    ul li .clz{color: #33f;}
    li .clz{color: #f33;}
    </style>
    
    <ul>
        <li><span class="clz">Hello World!</span></li>
    </ul>
    

    如果按照 W3C 规范来计算优先级, 那么会计算出:

    第一条的优先级: a=0, b=0, c=1, d=2
    第二条的优先级: a=0, b=0, c=1, d=1
    

    Continue reading »

    Posted by ideawu at 2015-11-11 16:26:18 Tags: ,
  • 2015-08-21

    CSS 样式规则的匹配算法实现

    Views: 28749 | No Comments

    CSS 的完整英文名称是: Cascading Style Sheets, 级联样式表. 除了可以定义丰富的样式, 以及进行界面控件布局外, CSS 最重要的特性便是名字中的"级联(Cascading)"一词. 级联代表了父子关联, 天生便是和数据结构中的"树"相关的.

    我创建的 CocoaUI iOS UI 框架, 是一个使用 CSS 进行 iOS 上流式布局的开发框架, 极大地方便了 iOS 应用的界面开发, 轻松适配多种屏幕. 因为 CocoaUI 使用 CSS 来进行界面布局和定义界面样式, 所以需要对 CSS 的样式规则进行匹配, 将某一条 CSS 样式作用到某一个 UIView(IView) 上面.

    Continue reading »

    Posted by ideawu at 2015-08-21 15:49:14 Tags: , , ,
  • 2015-03-25

    流式布局的原理和代码实现

    Views: 25845 | 2 Comments

    最简单的流式布局模型, 其实就是: 靠左, 靠右, 或者堆叠. 根据这个简单的理论, 可以用两个栈(Stack)数据结构, 一个表示靠左边的控件列表, 另一个表示靠右边的控件列表, 即可实现流式布局模型.

    用伪代码表示如下:

    // 视图控件
    class View{
        private FlowLayouter layouter;
        
        // 当控件发生 frame 改变后, 调用此方法标记为需要重新布局
        void setNeedsLayout(){
            View view = this;
            while(view){
                view.markNeedsLayout();
                // 当控件需要重新布局时, 一般地, 它的父节点也需要重新布局
                view = view.parent;
            }
        }
        
        void layout(){
            for(View child in this.children){
                this.layouter.place(child);
            }
        }
    }
    
    // 流式布局管理器
    class FlowLayouter{
        private Stack leftViews;
        private Stack rightViews;
        
        void place(View child){
            Position pos;
            child.layout(); // 子节点先进行布局
            while(!this.spaceFits(child)){
                if(child.floatLeft){
                    View view = this.leftViews.pop();
                    pos = view.pos;
                    // 当被移除的节点比其它节点更高时, 继续移除
                    while(pos.y > this.leftViews.last.y){
                        View view = this.leftViews.pop();
                        pos = view.pos;
                    }
                }
                if(child.floatRight){
                    View view = this.rightViews.pop();
                    pos = view.pos;
                    // 当被移除的节点比其它节点更高时, 继续移除
                    while(pos.y > this.rightViews.last.y){
                        View view = this.rightViews.pop();
                        pos = view.pos;
                    }
                }
            }
            
            // place child here
            child.pos = pos;
            
            if(child.floatLeft){
                this.leftViews.push(child.pos);
            }
            if(child.floatRight){
                this.rightViews.push(child.pos);
            }
        }
    }
    

    这段代码最重要的是两点:

    1. 当某个控件发生改变时, 它需要重新布局. 同时, 它的父节点, 以及父节点的父节点, 一直到节点树的根节点, 都需要重新布局. 当然, 这是性能最差的方案, 优化的思路就是减少需要重新布局的节点的数量, 这需要发动每个人的聪明才智来想.

    2. 用两个 Stack 来分别表示靠左的和靠右节点列表. 如果当前的空白空间不足以放下一个控件, 那么, 尝试从节点列表中移除一个节点, 这样, 这个布局区域就空出来了一些空间. 当然, 这个空间应该往下移, 不能和被移除的节点所占据的空间重叠. 因为流式布局的基本原理就是不重叠(除非通过特殊设定, 如负数的偏移量).

    有了这个简单的流式布局模型, 你可以在所有最基本的绝对定位的 GUI 库上面实现功能强大的流式布局, 例如, iOS 的 UIKit 不支持流式布局, 你可以根据上面的代码扩展, 给 iOS 界面开发加上流式布局功能.

    流式布局其实是非常有趣的一项功能, 它的模型很简洁, 但功能强大且应用广泛. GUI 界面的本质是树, 树是简洁而优美的, 而流式布局使用的数据结构是 Stack, 又是一种非常基础的数据结构.

    说句题外话, 我已经实现了 iOS 系统上面的 UI 流式布局 - CocoaUI, 你可以试用下.

    Posted by ideawu at 2015-03-25 14:33:48 Tags: ,
|<<<1>>>| 1/1 Pages, 3 Results.