一个自定义UI控件的优化历程

之前实现了一个尺子,效果如图:


考虑到以后其他地方可能还会用到,就做成了一个pod库,放到了github上,传送门
后来使用过程中发现并修改了很多问题,来总结一下优化历程:

最开始是用drawRect的方式实现的,就是在drawRect方法中,把每一条刻度都画出来,核心方法如下:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [self.rulerLineColor set];
    CGFloat startPoint = self.rulerMargin;
    for (int i = 0; i <= (self.maxValue - self.minValue); i++) {
        CGContextSetLineWidth(context, 1);
        startPoint = i * self.rulerSpacing + self.rulerMargin;
        CGFloat endPoint = 0;
        if (i % 5 == 0) {
            endPoint = self.longLineDistance; 
        } else {
            endPoint = self.shortLineDistance;
        }
        CGContextMoveToPoint(context, startPoint, 0);
        CGContextAddLineToPoint(context, startPoint, endPoint);
        CGContextStrokePath(context);
    }
    CGContextMoveToPoint(context, self.rulerMargin, 0);
    CGContextAddLineToPoint(context, startPoint, 0);
    CGContextStrokePath(context);
}

(具体代码见tag 1.0.0)

这个方法比较直观,所见即所得嘛,很容易想到,但很快就发现了一个大问题:
太占内存了!!!
如果只有100条刻度还好,占用内存也就几M,但实际场景是这个是用来选择身高的,精度要到0.1,所以刻度数量是原来的10倍。。。
那内存就吃不消了,一个小控件要几十M,那来两三个内存不就炸了。。。
至于为什么drawRect会这么站内存,可以参考客:
内存恶鬼drawRect
内存恶鬼drawRect(续:答疑篇)

所以就迎来了第一次主要的优化:

使用CALayer来绘图,弃用drawRect方式;

思路跟原来没有什么大的变化,只是不再使用drawRect的方法,改为在initWithFrame方法中,直接添加layer,核心方法如下:

- (void)setupUI {
    CGFloat startPoint = self.rulerMargin;
    for (int i = 0; i <= (self.maxValue - self.minValue) / self.accuracy; i++) {
        CALayer *subLayer = [CALayer layer];
        startPoint = i * self.rulerSpacing + self.rulerMargin;
        CGFloat endPoint = 0;
        if (i % 10 == 0) {
            endPoint = self.longLineDistance; 
        }
        else if (i % 5 == 0) {
            endPoint = (self.longLineDistance + self.shortLineDistance) / 2.0;
        }
        else {
            endPoint = self.shortLineDistance;
        }
        subLayer.frame = CGRectMake(startPoint, 0, 1, endPoint);
        subLayer.backgroundColor = self.rulerLineColor.CGColor;
        [self.layer addSublayer:subLayer];
    }
    CALayer *layer = [CALayer layer];
    layer.frame = CGRectMake(self.rulerMargin, 0, startPoint - self.rulerMargin, 1);
    layer.backgroundColor = self.rulerLineColor.CGColor;
    [self.layer addSublayer:layer];
}

(具体代码见tag 1.3.1)

这个就是采用了上面提到的两篇博客提到的优化方式,效果也确实很明显,内存占用很小很小了;

然而计划赶不上变化,产品经理提出了新的需求,要在一个界面上显示多个尺子,而且可以随时隐藏或者显示;
所以就又碰到了一个大问题:
绘制太慢,会卡住主线程!!!
修改UI的操作只能在主线程操作,而要同时画出几个尺子,每个尺子都有成百上千个subLayer,这卡了真不能怪手机,只能怪设计不合理。。。(产品经理:怪我咯~)
其实不是产品设计不合理,是UI控件设计不合理,尺子这种大面积重复的界面,肯定是可以复用的啦,怎么能直接画这么长呢!!!
所以就迎来了第二次主要优化:

使用UICollectionView的复用机制重构整个控件

(具体代码见tag 2.1.0)
这个思路就跟之前有比较大的不同了,要把一个完整的尺子拆成N个复用的cell;
思前想后,我最后采用的方式是:不管刻度的间距是多少或者尺子的精度是多少,每个cell固定显示10个刻度;这样就可以比较容易的确定cell的大小和个数。
还有几个细节优化的地方:

  1. cell里面固定有几个subLayer,是在初始化的时候就生成好的,在cellForRow方法中,只需要修改他们的frame,颜色等属性就可以;
  2. 原来的markView,是用一个View实现的,当初是为了能用autoLayout,现在直接用个CAShapeLayer实现,手动计算frame来确定位置

最终效果如图:

rulerView2.gif

后续:

理论上,在cellForRow中修改View的frame等属性也是比较消耗性能的操作,在cell初始化的时候,就把各种属性都设置对才是更理想的做法;
目前还没想到有什么好的方式可以实现,因为cell类跟rulerView的实例联系不起来。。。
同学们有什么好的思路,望不吝赐教~

有什么问题,欢迎讨论~
也可以直接去github(https://github.com/Phelthas/LXMRulerView ) 上提交issue或者pull request

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 其实当时也不懂为何我那么得空,坐在那儿两个小时,只为了画这些圈圈...... 圈圈+线条=莫名奇妙的画作........
    雪樱思薰XYSX阅读 202评论 3 6
  • 岁月静好,老爸的脑门倍儿亮
    昙花舞阅读 120评论 0 0
  • 见过花落,回望花开,花开易见却未见,花落难寻空留痕。青春里的爱恋总是需要珍惜和争取,不然等到花开的时候却始终等不到...
    Renzo阅读 439评论 0 0