• 2015-06-17

    iOS流式布局UI框架CocoaUI开源

    Views: 10128 | 1 Comment

    CocoaUI 是一个强大的 iOS UI 框架, 使用 Web 开发者熟悉的 HTML+CSS 流式布局方式, 轻松地开发 iOS 原生 App 的界面.

    CocoaUI 的特性主要包括:

    • 高效的原生界面, 非低效的 WebView 控件方式
    • 自适应(Adaptive)动态流式布局, 轻松适配多种屏幕尺寸
    • 采用简洁高效的 HTML+CSS 语法定义布局(Layout)和展现(Appearance)

    Continue reading »

    Posted by ideawu at 2015-06-17 17:50:00 Tags:
  • 2015-03-25

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

    Views: 15398 | 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: ,
  • 2015-03-08

    iOS界面响应式布局方式对比

    Views: 13548 | 2 Comments

    iPhone 手机的成功, iOS 操作系统功不可没. 而 iOS 操作系统的成功, 与早期 iPhone 单一的屏幕分辨率也有极大的关系. 不客气地说, 正因为早期 iPhone 手机只有一个分辨率, iOS 操作系统和其上面的 App 才不需要关心所谓的"响应式布局", "流式布局", "自动布局"这些技术, 它们只使用绝对定位的布局 - 每一个控件的大小和位置都是定死的, 几乎不变. 这样, iOS 应用开发者把精力放在了界面外观和交互体验, 最终促成了 iPhone/iOS 的成功.

    不过, 从 iPad 的出现, 到 iPhone 5 发布, 以及后面的 iPhone 6/6+, iPhone/iOS 手机的屏幕分辨率开始多样化了, 这时, 界面布局便不能死守着绝对定位布局了.

    为了解决这个问题, 苹果的方案是"Auto Resizing"和"Auto Layout", 特别是后者, 解决了界面动态布局的问题.

    Continue reading »

    Posted by ideawu at 2015-03-08 15:36:31 Tags: ,
  • 2015-02-03

    iOS 使用 RSA 加密, 只需要公钥

    Views: 16855 | No Comments

    在 iOS 上, 加密被和安全性进行了强绑定, 所以, 你不能只做加密(至少公开文档不告诉你如何只做加密). 但事实上, 很多时候我们加密, 并不是要求 100% 的安全, 只是希望能得到加密本身所带来的安全, 既不考虑数据重放, 也不考虑第三者攻击, 也不考虑身份伪装. 我们仅仅是需要 - 加密, RSA 非对称加密. 物理上的和系统上的安全我们会想尽全部办法来解决, 不需要加密模块来管.

    但是, 苹果不公开允许这样做, 所以 iOS 上的 Cocoa API 就没有简单的这样的加密函数:

    ret = rsa_encrypt(src_data, public_key);
    

    例如, 苹果的 SecKeyEncrypt() 函数需要 .der 证书, 而公钥只是证书的一部分. 所以, 如果你只有公钥, 你是不能直接使用这个函数的. 幸运的是, iOS 可以使用自己产生的公钥, 所以, 你要做的是把你的公钥伪装成是 iOS 产生的.

    这篇文章, 介绍了如何伪装公钥. 伪装完后, 你就可以直接使用 SecKeyEncrypt() 函数来进行 RSA 公钥加密了.

    完整的代码我放在 GitHub 上了.

    Posted by ideawu at 2015-02-03 17:49:57 Tags: ,
  • 2013-06-12

    遍历NSString每一个字符的正确方式!

    Views: 23964 | No Comments

    最近在处理Cocoa NSString时, 遇到一些字符编码的问题, 从而引出一个遍历NSString每一个字符的"正确"方式! 很有趣.

    NSString是UTF-16编码的, 也就是16位的unichar字符的序列. 所以, 一般遍历其每一个字符的方法就是:

    for(int i=0; i<str.length; i++){
        unichar ch = [str characterAtIndex: i];
    }
    

    但是, 我们平常书写的字符, 并不全部都是用唯一的一个16位字符来表示, 而是有一部分用两个16位字符来表示, 这就是surrogate pairs的概念. 如果还是用上面的方法遍历字符串, 就会出现"断字". 例如图中这个Apple Color Emoji的"THUMBS UP SIGN"字符, 其实是用2个16位unichar来表示, 它的Unicode是U+1F44D, 用(U+D83D U+DC4D)两个字符来表示.

    还好, NSString的rangeOfComposedCharacterSequencesForRange:rangeOfComposedCharacterSequenceAtIndex:两个方法可以用来处理这种情况. 所以, 真正正确的遍历NSString的每一个字符的方法就是这样了:

    NSRange range;
    for(int i=0; i<str.length; i+=range.length){
        range = [str rangeOfComposedCharacterSequenceAtIndex:i];
        NSString *s = [str attributedSubstringFromRange:range];
    }
    

    一次遍历一个子串, 而不是遍历一个unichar了.

    相关资料:

    Posted by ideawu at 2013-06-12 12:26:39
  • 2013-04-14

    Cocoa处理JSON转换, 兼谈计算机语言的哲学

    Views: 15059 | 3 Comments

    用了下 Objective-C Cocoa 里的 JSON 相关类 NSJSONSerialization, 发现简单的事情突然变得太复杂了. 想想用 php 语言的时候, 如果想把 php 语言对象转成字符串, 直接 json_encode(); 如果想把网络或者文件中的一段二进制数据(JSON 字符串)转成 php 对象, 直接 json_decode().

    但是, 在 Cocoa 里就不那么直接了. 首先, 你会遇到字符编码的问题, 所以你得到的和操作的不能是字符串, 而是 NSData. 其次, NSJSONSerialization 无谓地增加了限制, 顶层 Objective-C 对象只能是数组和字典.

    我不想探讨这里面的原因, 我当然知道这里面的原因, 我只是说, 这些原因可以避免.

    第一, 为解决后一个限制, 我可以做一些封装, 支持语言的整数对象和字符串对象(非常重要)直接转成 JSON 字符串, 而忽略所谓的 NSData(后面讲为什么 NSData 不是一个好东西).

    Continue reading »

    Posted by ideawu at 2013-04-14 15:51:29
|<<<123>>>| 3/3 Pages, 18 Results.